From a9828ec6bc0b7e19a65f7e13daa8bd35a926a753 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 1 Oct 2009 11:33:03 +0000 Subject: ethtool: Remove support for obsolete string query operations The in-tree implementations have all been converted to get_sset_count(). Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- net/core/ethtool.c | 58 ++++++++++-------------------------------------------- 1 file changed, 10 insertions(+), 48 deletions(-) (limited to 'net') diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 4c12ddb5f5e..e1951084b97 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); @@ -684,16 +677,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 +715,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 +766,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); -- cgit v1.2.3 From b3a5b6cc7cab89dcc3301add750f88019d910a2b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 24 Sep 2009 12:16:51 +0000 Subject: icmp: No need to call sk_write_space() We can make icmp messages tx completion callback a litle bit faster. Setting SOCK_USE_WRITE_QUEUE sk flag tells sock_wfree() to not call sk_write_space() on a socket we know no thread is posssibly waiting for write space. (on per cpu kernel internal icmp sockets only) This avoids the sock_def_write_space() call and read_lock(&sk->sk_callback_lock)/read_unlock(&sk->sk_callback_lock) calls as well. We avoid three atomic ops. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') 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; } -- cgit v1.2.3 From 0835acfe72e43b2f9bd46ec8c0d219e94c3525e0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 30 Sep 2009 13:03:33 +0000 Subject: pktgen: Avoid dirtying skb->users when txq is full We can avoid two atomic ops on skb->users if packet is not going to be sent to the device (because hardware txqueue is full) Signed-off-by: Eric Dumazet Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/core/pktgen.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b69455217ed..e856ab0d074 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 */ -- cgit v1.2.3 From 977750076d98c7ff6cbda51858bb5a5894a9d9ab Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 2 Oct 2009 06:56:41 +0000 Subject: af_packet: add interframe drop cmsg (v6) Add Ancilliary data to better represent loss information I've had a few requests recently to provide more detail regarding frame loss during an AF_PACKET packet capture session. Specifically the requestors want to see where in a packet sequence frames were lost, i.e. they want to see that 40 frames were lost between frames 302 and 303 in a packet capture file. In order to do this we need: 1) The kernel to export this data to user space 2) The applications to make use of it This patch addresses item (1). It does this by doing the following: A) Anytime we drop a frame for which we would increment po->stats.tp_drops, we also no increment a stats called po->stats.tp_gap. B) Every time we successfully enqueue a frame to sk_receive_queue, we record the value of po->stats.tp_gap in skb->mark. skb->cb would nominally be the place to record this, but since all the space there is used up, we're overloading skb->mark. Its safe to do since any enqueued packet is guaranteed to be unshared at this point, and skb->mark isn't used for anything else in the rx path to the application. After we record tp_gap in the skb, we zero po->stats.tp_gap. This allows us to keep a counter of the number of frames lost between any two enqueued packets C) When the application goes to dequeue a frame from the packet socket, we look at skb->mark for that frame. If it is non-zero, we add a cmsg chunk to the msghdr of level SOL_PACKET and type PACKET_GAPDATA. Its a 32 bit integer that represents the number of frames lost between this packet and the last previous frame received. Note there is a chance that if there is frame loss after a receive, and then the socket is closed, some gap data might be lost. This is covered by the use of the PACKET_AUXDATA socket option, which gives total loss data. With a bit of math, the final gap can be determined that way. I've tested this patch myself, and it works well. Signed-off-by: Neil Horman Signed-off-by: Eric Dumazet include/linux/if_packet.h | 2 ++ net/packet/af_packet.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) Signed-off-by: David S. Miller --- include/linux/if_packet.h | 2 ++ net/packet/af_packet.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'net') diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index dea7d6b7cf9..e5d200f53fc 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -48,11 +48,13 @@ struct sockaddr_ll #define PACKET_RESERVE 12 #define PACKET_TX_RING 13 #define PACKET_LOSS 14 +#define PACKET_GAPDATA 15 struct tpacket_stats { unsigned int tp_packets; unsigned int tp_drops; + unsigned int tp_gap; }; struct tpacket_auxdata diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d7ecca0a0c0..d398a9bf690 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -523,6 +523,31 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk, return res; } +/* + * If we've lost frames since the last time we queued one to the + * sk_receive_queue, we need to record it here. + * This must be called under the protection of the socket lock + * to prevent racing with other softirqs and user space + */ +static inline void record_packet_gap(struct sk_buff *skb, + struct packet_sock *po) +{ + /* + * We overload the mark field here, since we're about + * to enqueue to a receive queue and no body else will + * use this field at this point + */ + skb->mark = po->stats.tp_gap; + po->stats.tp_gap = 0; + return; + +} + +static inline __u32 check_packet_gap(struct sk_buff *skb) +{ + return skb->mark; +} + /* This function makes lazy skb cloning in hope that most of packets are discarded by BPF. @@ -626,6 +651,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, spin_lock(&sk->sk_receive_queue.lock); po->stats.tp_packets++; + record_packet_gap(skb, po); __skb_queue_tail(&sk->sk_receive_queue, skb); spin_unlock(&sk->sk_receive_queue.lock); sk->sk_data_ready(sk, skb->len); @@ -634,6 +660,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, drop_n_acct: spin_lock(&sk->sk_receive_queue.lock); po->stats.tp_drops++; + po->stats.tp_gap++; spin_unlock(&sk->sk_receive_queue.lock); drop_n_restore: @@ -811,6 +838,7 @@ drop: ring_is_full: po->stats.tp_drops++; + po->stats.tp_gap++; spin_unlock(&sk->sk_receive_queue.lock); sk->sk_data_ready(sk, 0); @@ -1418,6 +1446,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; int copied, err; struct sockaddr_ll *sll; + __u32 gap; err = -EINVAL; if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) @@ -1496,6 +1525,10 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); } + gap = check_packet_gap(skb); + if (gap) + put_cmsg(msg, SOL_PACKET, PACKET_GAPDATA, sizeof(__u32), &gap); + /* * Free or return the buffer as appropriate. Again this * hides all the races and re-entrancy issues from us. -- cgit v1.2.3 From 16c6cf8bb471392fd09b48b7c27e7d83a446b4bc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 20 Sep 2009 10:35:36 +0000 Subject: ipv4: fib table algorithm performance improvement The FIB algorithim for IPV4 is set at compile time, but kernel goes through the overhead of function call indirection at runtime. Save some cycles by turning the indirect calls to direct calls to either hash or trie code. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/ip_fib.h | 25 ++++++++++++++----------- net/ipv4/fib_frontend.c | 26 +++++++++++++------------- net/ipv4/fib_hash.c | 25 ++++++++++--------------- net/ipv4/fib_rules.c | 2 +- net/ipv4/fib_trie.c | 26 ++++++++++---------------- 5 files changed, 48 insertions(+), 56 deletions(-) (limited to 'net') diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index ef91fe924ba..68fd5ebd094 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -144,18 +144,21 @@ struct fib_table { struct hlist_node tb_hlist; u32 tb_id; int tb_default; - int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res); - int (*tb_insert)(struct fib_table *, struct fib_config *); - int (*tb_delete)(struct fib_table *, struct fib_config *); - int (*tb_dump)(struct fib_table *table, struct sk_buff *skb, - struct netlink_callback *cb); - int (*tb_flush)(struct fib_table *table); - void (*tb_select_default)(struct fib_table *table, - const struct flowi *flp, struct fib_result *res); - unsigned char tb_data[0]; }; +extern int fib_table_lookup(struct fib_table *tb, const struct flowi *flp, + struct fib_result *res); +extern int fib_table_insert(struct fib_table *, struct fib_config *); +extern int fib_table_delete(struct fib_table *, struct fib_config *); +extern int fib_table_dump(struct fib_table *table, struct sk_buff *skb, + struct netlink_callback *cb); +extern int fib_table_flush(struct fib_table *table); +extern void fib_table_select_default(struct fib_table *table, + const struct flowi *flp, + struct fib_result *res); + + #ifndef CONFIG_IP_MULTIPLE_TABLES #define TABLE_LOCAL_INDEX 0 @@ -182,11 +185,11 @@ static inline int fib_lookup(struct net *net, const struct flowi *flp, struct fib_table *table; table = fib_get_table(net, RT_TABLE_LOCAL); - if (!table->tb_lookup(table, flp, res)) + if (!fib_table_lookup(table, flp, res)) return 0; table = fib_get_table(net, RT_TABLE_MAIN); - if (!table->tb_lookup(table, flp, res)) + if (!fib_table_lookup(table, flp, res)) return 0; return -ENETUNREACH; } 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)); -- cgit v1.2.3 From 0bfbedb14a8a96c529341bec88991a92b41fac72 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 5 Oct 2009 00:11:22 -0700 Subject: tunnels: Optimize tx path We currently dirty a cache line to update tunnel device stats (tx_packets/tx_bytes). We better use the txq->tx_bytes/tx_packets counters that already are present in cpu cache, in the cache line shared with txq->_xmit_lock This patch extends IPTUNNEL_XMIT() macro to use txq pointer provided by the caller. Also &tunnel->dev->stats can be replaced by &dev->stats Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/ipip.h | 6 +++--- net/ipv4/ip_gre.c | 5 +++-- net/ipv4/ipip.c | 5 +++-- net/ipv6/sit.c | 5 +++-- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/ipip.h b/include/net/ipip.h index 87acf8f3a15..0159221a850 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -42,9 +42,9 @@ struct ip_tunnel_prl_entry ip_select_ident(iph, &rt->u.dst, NULL); \ \ err = ip_local_out(skb); \ - if (net_xmit_eval(err) == 0) { \ - stats->tx_bytes += pkt_len; \ - stats->tx_packets++; \ + if (likely(net_xmit_eval(err) == 0)) { \ + txq->tx_bytes += pkt_len; \ + txq->tx_packets++; \ } else { \ stats->tx_errors++; \ stats->tx_aborted_errors++; \ 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/ipv6/sit.c b/net/ipv6/sit.c index dbd19a78ca7..99da272951d 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -555,7 +555,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; @@ -688,7 +689,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; } -- cgit v1.2.3 From 7ffbe3fdace0bdfcdab8dc6c77506feda0871f79 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Oct 2009 05:15:27 +0000 Subject: net: introduce NETDEV_POST_INIT notifier For various purposes including a wireless extensions bugfix, we need to hook into the netdev creation before before netdev_register_kobject(). This will also ease doing the dev type assignment that Marcel was working on for cfg80211 drivers w/o touching them all. Signed-off-by: Johannes Berg Signed-off-by: Marcel Holtmann Signed-off-by: David S. Miller --- include/linux/notifier.h | 1 + net/core/dev.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'net') diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 44428d247db..29714b8441b 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -201,6 +201,7 @@ static inline int notifier_to_errno(int ret) #define NETDEV_PRE_UP 0x000D #define NETDEV_BONDING_OLDTYPE 0x000E #define NETDEV_BONDING_NEWTYPE 0x000F +#define NETDEV_POST_INIT 0x0010 #define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_RESTART SYS_DOWN diff --git a/net/core/dev.c b/net/core/dev.c index b8f74cfb1bf..a74c8fd6955 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4836,6 +4836,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; -- cgit v1.2.3 From 053a93dd126f68ba37973f95f00af6045fa7c957 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 2 Oct 2009 05:15:28 +0000 Subject: cfg80211: assign device type in netdev notifier callback Instead of having to modify every non-mac80211 for device type assignment, do this inside the netdev notifier callback of cfg80211. So all drivers that integrate with cfg80211 will export a proper device type. Signed-off-by: Marcel Holtmann Signed-off-by: David S. Miller --- net/mac80211/iface.c | 5 ----- net/wireless/core.c | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b8295cbd7e8..f6005adcbf9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -754,10 +754,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) @@ -789,7 +785,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, memcpy(ndev->dev_addr, local->hw.wiphy->perm_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/wireless/core.c b/net/wireless/core.c index 45b2be3274d..e6f02e98e5f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -625,6 +625,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 +645,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 -- cgit v1.2.3 From d519e17e2d01a0ee9abe083019532061b4438065 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Fri, 2 Oct 2009 09:26:12 +0000 Subject: net: export device speed and duplex via sysfs This patch exports the link-speed (in Mbps) and duplex of an interface via sysfs. This eliminates the need to use ethtool just to check the link-speed. Not requiring 'ethtool' and not relying on the SIOCETHTOOL ioctl should be helpful in an embedded environment where space is at a premium as well. NOTE: This patch also intentionally allows non-root users to check the link speed and duplex -- something not possible with ethtool. Here's some sample output: # cat /sys/class/net/eth0/speed 100 # cat /sys/class/net/eth0/duplex half # ethtool eth0 Settings for eth0: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Half 1000baseT/Full Supports auto-negotiation: Yes Advertised link modes: Not reported Advertised auto-negotiation: No Speed: 100Mb/s Duplex: Half Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: off Supports Wake-on: g Wake-on: g Current message level: 0x000000ff (255) Link detected: yes Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'net') diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 821d30918cf..effb78410eb 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), -- cgit v1.2.3 From bcdce7195e0eab55b37dbd53be53057f38006380 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Oct 2009 17:28:29 -0700 Subject: net: speedup sk_wake_async() An incoming datagram must bring into cpu cache *lot* of cache lines, in particular : (other parts omitted (hash chains, ip route cache...)) On 32bit arches : offsetof(struct sock, sk_rcvbuf) =0x30 (read) offsetof(struct sock, sk_lock) =0x34 (rw) offsetof(struct sock, sk_sleep) =0x50 (read) offsetof(struct sock, sk_rmem_alloc) =0x64 (rw) offsetof(struct sock, sk_receive_queue)=0x74 (rw) offsetof(struct sock, sk_forward_alloc)=0x98 (rw) offsetof(struct sock, sk_callback_lock)=0xcc (rw) offsetof(struct sock, sk_drops) =0xd8 (read if we add dropcount support, rw if frame dropped) offsetof(struct sock, sk_filter) =0xf8 (read) offsetof(struct sock, sk_socket) =0x138 (read) offsetof(struct sock, sk_data_ready) =0x15c (read) We can avoid sk->sk_socket and socket->fasync_list referencing on sockets with no fasync() structures. (socket->fasync_list ptr is probably already in cache because it shares a cache line with socket->wait, ie location pointed by sk->sk_sleep) This avoids one cache line load per incoming packet for common cases (no fasync()) We can leave (or even move in a future patch) sk->sk_socket in a cold location Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 3 ++- net/socket.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index 1621935aad5..98398bdec57 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -504,6 +504,7 @@ enum sock_flags { SOCK_TIMESTAMPING_SOFTWARE, /* %SOF_TIMESTAMPING_SOFTWARE */ SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SOF_TIMESTAMPING_RAW_HARDWARE */ SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SOF_TIMESTAMPING_SYS_HARDWARE */ + SOCK_FASYNC, /* fasync() active */ }; static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) @@ -1396,7 +1397,7 @@ static inline unsigned long sock_wspace(struct sock *sk) static inline void sk_wake_async(struct sock *sk, int how, int band) { - if (sk->sk_socket && sk->sk_socket->fasync_list) + if (sock_flag(sk, SOCK_FASYNC)) sock_wake_async(sk->sk_socket, how, band); } diff --git a/net/socket.c b/net/socket.c index 75655365b5f..d53ad11558c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1100,11 +1100,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); } -- cgit v1.2.3 From ee5e81f00051b5c373c8de16e3604fd6d3be699e Mon Sep 17 00:00:00 2001 From: Ilia K Date: Wed, 16 Sep 2009 05:53:07 +0000 Subject: add vif using local interface index instead of IP When routing daemon wants to enable forwarding of multicast traffic it performs something like: struct vifctl vc = { .vifc_vifi = 1, .vifc_flags = 0, .vifc_threshold = 1, .vifc_rate_limit = 0, .vifc_lcl_addr = ip, /* <--- ip address of physical interface, e.g. eth0 */ .vifc_rmt_addr.s_addr = htonl(INADDR_ANY), }; setsockopt(fd, IPPROTO_IP, MRT_ADD_VIF, &vc, sizeof(vc)); This leads (in the kernel) to calling vif_add() function call which search the (physical) device using assigned IP address: dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr); The current API (struct vifctl) does not allow to specify an interface other way than using it's IP, and if there are more than a single interface with specified IP only the first one will be found. The attached patch (against 2.6.30.4) allows to specify an interface by its index, instead of IP address: struct vifctl vc = { .vifc_vifi = 1, .vifc_flags = VIFF_USE_IFINDEX, /* NEW */ .vifc_threshold = 1, .vifc_rate_limit = 0, .vifc_lcl_ifindex = if_nametoindex("eth0"), /* NEW */ .vifc_rmt_addr.s_addr = htonl(INADDR_ANY), }; setsockopt(fd, IPPROTO_IP, MRT_ADD_VIF, &vc, sizeof(vc)); Signed-off-by: Ilia K. === modified file 'include/linux/mroute.h' Signed-off-by: David S. Miller --- include/linux/mroute.h | 13 +++++++++---- net/ipv4/ipmr.c | 12 +++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 08bc776d05e..d5f69151f69 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -59,13 +59,18 @@ struct vifctl { unsigned char vifc_flags; /* VIFF_ flags */ unsigned char vifc_threshold; /* ttl limit */ unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ - struct in_addr vifc_lcl_addr; /* Our address */ + union { + struct in_addr vifc_lcl_addr; /* Local interface address */ + int vifc_lcl_ifindex; /* Local interface index */ + }; struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */ }; -#define VIFF_TUNNEL 0x1 /* IPIP tunnel */ -#define VIFF_SRCRT 0x2 /* NI */ -#define VIFF_REGISTER 0x4 /* register vif */ +#define VIFF_TUNNEL 0x1 /* IPIP tunnel */ +#define VIFF_SRCRT 0x2 /* NI */ +#define VIFF_REGISTER 0x4 /* register vif */ +#define VIFF_USE_IFINDEX 0x8 /* use vifc_lcl_ifindex instead of + vifc_lcl_addr to find an interface */ /* * Cache manipulation structures for mrouted and PIMd 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); -- cgit v1.2.3 From fa857afcf77da669eb6b7031ec07ad14b912c307 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Tue, 22 Sep 2009 23:43:14 +0000 Subject: ipv6 sit: 6rd (IPv6 Rapid Deployment) Support. 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. Original patch was done by Alexandre Cassen based on old Internet-Draft. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/if_tunnel.h | 11 ++++ include/net/ipip.h | 13 +++++ net/ipv6/Kconfig | 19 +++++++ net/ipv6/sit.c | 124 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 159 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 5a9aae4adb4..c53c8e01694 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -15,6 +15,10 @@ #define SIOCADDPRL (SIOCDEVPRIVATE + 5) #define SIOCDELPRL (SIOCDEVPRIVATE + 6) #define SIOCCHGPRL (SIOCDEVPRIVATE + 7) +#define SIOCGET6RD (SIOCDEVPRIVATE + 8) +#define SIOCADD6RD (SIOCDEVPRIVATE + 9) +#define SIOCDEL6RD (SIOCDEVPRIVATE + 10) +#define SIOCCHG6RD (SIOCDEVPRIVATE + 11) #define GRE_CSUM __cpu_to_be16(0x8000) #define GRE_ROUTING __cpu_to_be16(0x4000) @@ -51,6 +55,13 @@ struct ip_tunnel_prl { /* PRL flags */ #define PRL_DEFAULT 0x0001 +struct ip_tunnel_6rd { + struct in6_addr prefix; + __be32 relay_prefix; + __u16 prefixlen; + __u16 relay_prefixlen; +}; + enum { IFLA_GRE_UNSPEC, diff --git a/include/net/ipip.h b/include/net/ipip.h index 0159221a850..86f1c8bd040 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -7,6 +7,15 @@ /* Keep error state on tunnel for 30 sec */ #define IPTUNNEL_ERR_TIMEO (30*HZ) +/* 6rd prefix/relay information */ +struct ip_tunnel_6rd_parm +{ + struct in6_addr prefix; + __be32 relay_prefix; + u16 prefixlen; + u16 relay_prefixlen; +}; + struct ip_tunnel { struct ip_tunnel *next; @@ -23,6 +32,10 @@ struct ip_tunnel struct ip_tunnel_parm parms; + /* for SIT */ +#ifdef CONFIG_IPV6_SIT_6RD + struct ip_tunnel_6rd_parm ip6rd; +#endif struct ip_tunnel_prl_entry *prl; /* potential router list */ unsigned int prl_count; /* # of entries in PRL */ }; diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ead6c7a42f4..f5619982745 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 Development (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/sit.c b/net/ipv6/sit.c index 99da272951d..6955654262a 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -161,6 +161,21 @@ 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 ip_tunnel *t, struct sit_net *sitn) +{ +#ifdef CONFIG_IPV6_SIT_6RD + 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) { @@ -213,6 +228,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, dev_hold(dev); + ipip6_tunnel_clone_6rd(t, sitn); + ipip6_tunnel_link(sitn, nt); return nt; @@ -532,17 +549,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(tunnel->ip6rd.prefix.s6_addr32[pbw0]) << pbi0) >> + tunnel->ip6rd.relay_prefixlen; + + pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen; + if (pbi1 > 0) + d |= ntohl(tunnel->ip6rd.prefix.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; } @@ -596,7 +637,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; @@ -786,9 +827,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))) { @@ -799,9 +846,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: @@ -922,6 +985,51 @@ 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; + relay_prefix = ip6rd.relay_prefix & + htonl(0xffffffffUL << + (32 - ip6rd.relay_prefixlen)); + 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(t, sitn); + + err = 0; + break; +#endif + default: err = -EINVAL; } -- cgit v1.2.3 From 2d37a186cedc51502dbee71c16ae0fbd9114d62c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 1 Oct 2009 19:14:46 +0000 Subject: Use sk_mark for routing lookup in more places Here is a followup on this area, thanks. [RFC] af_packet: fill skb->mark at xmit skb->mark may be used by classifiers, so fill it in case user set a SO_MARK option on socket. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/packet/af_packet.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d398a9bf690..efc1174af71 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; @@ -884,6 +885,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) { @@ -1153,6 +1155,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 -- cgit v1.2.3 From d250a5f90e53f5e150618186230795352d154c88 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 2 Oct 2009 10:32:18 +0000 Subject: pkt_sched: gen_estimator: Dont report fake rate estimators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jarek Poplawski a écrit : > > > Hmm... So you made me to do some "real" work here, and guess what?: > there is one serious checkpatch warning! ;-) Plus, this new parameter > should be added to the function description. Otherwise: > Signed-off-by: Jarek Poplawski > > Thanks, > Jarek P. > > PS: I guess full "Don't" would show we really mean it... Okay :) Here is the last round, before the night ! Thanks again [RFC] pkt_sched: gen_estimator: Don't report fake rate estimators We currently send TCA_STATS_RATE_EST elements to netlink users, even if no estimator is running. # tc -s -d qdisc qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 112833764978 bytes 1495081739 pkt (dropped 0, overlimits 0 requeues 0) rate 0bit 0pps backlog 0b 0p requeues 0 User has no way to tell if the "rate 0bit 0pps" is a real estimation, or a fake one (because no estimator is active) After this patch, tc command output is : $ tc -s -d qdisc qdisc pfifo_fast 0: dev eth0 root bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 561075 bytes 1196 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 We add a parameter to gnet_stats_copy_rate_est() function so that it can use gen_estimator_active(bstats, r), as suggested by Jarek. This parameter can be NULL if check is not necessary, (htb for example has a mandatory rate estimator) Signed-off-by: Eric Dumazet Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- include/net/gen_stats.h | 1 + net/core/gen_stats.c | 8 +++++++- net/sched/act_api.c | 3 ++- net/sched/sch_api.c | 2 +- net/sched/sch_cbq.c | 2 +- net/sched/sch_drr.c | 2 +- net/sched/sch_hfsc.c | 2 +- net/sched/sch_htb.c | 2 +- 8 files changed, 15 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h index c1488553e34..eb87a1447ae 100644 --- a/include/net/gen_stats.h +++ b/include/net/gen_stats.h @@ -30,6 +30,7 @@ extern int gnet_stats_start_copy_compat(struct sk_buff *skb, int type, extern int gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b); extern int gnet_stats_copy_rate_est(struct gnet_dump *d, + const struct gnet_stats_basic_packed *b, struct gnet_stats_rate_est *r); extern int gnet_stats_copy_queue(struct gnet_dump *d, struct gnet_stats_queue *q); 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/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; -- cgit v1.2.3 From d73d3a8cb4723e161589864741d8528d70b350eb Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 5 Oct 2009 10:59:58 +0000 Subject: ethtool: Add reset operation After updating firmware stored in flash, users may wish to reset the relevant hardware and start the new firmware immediately. This should not be completely automatic as it may be disruptive. A selective reset may also be useful for debugging or diagnostics. This adds a separate reset operation which takes flags indicating the components to be reset. Drivers are allowed to reset only a subset of those requested, and must indicate the actual subset. This allows the use of generic component masks and some future expansion. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- include/linux/ethtool.h | 32 ++++++++++++++++++++++++++++++++ net/core/ethtool.c | 23 +++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'net') diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index aa0dcb3833d..eb1a48da2d4 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -498,6 +498,7 @@ struct ethtool_ops { int (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *); int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); int (*flash_device)(struct net_device *, struct ethtool_flash *); + int (*reset)(struct net_device *, u32 *); }; #endif /* __KERNEL__ */ @@ -555,6 +556,7 @@ struct ethtool_ops { #define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */ #define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ #define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ +#define ETHTOOL_RESET 0x00000034 /* Reset hardware */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET @@ -685,4 +687,34 @@ struct ethtool_ops { #define RX_CLS_FLOW_DISC 0xffffffffffffffffULL +/* Reset flags */ +/* The reset() operation must clear the flags for the components which + * were actually reset. On successful return, the flags indicate the + * components which were not reset, either because they do not exist + * in the hardware or because they cannot be reset independently. The + * driver must never reset any components that were not requested. + */ +enum ethtool_reset_flags { + /* These flags represent components dedicated to the interface + * the command is addressed to. Shift any flag left by + * ETH_RESET_SHARED_SHIFT to reset a shared component of the + * same type. + */ + ETH_RESET_MGMT = 1 << 0, /* Management processor */ + ETH_RESET_IRQ = 1 << 1, /* Interrupt requester */ + ETH_RESET_DMA = 1 << 2, /* DMA engine */ + ETH_RESET_FILTER = 1 << 3, /* Filtering/flow direction */ + ETH_RESET_OFFLOAD = 1 << 4, /* Protocol offload */ + ETH_RESET_MAC = 1 << 5, /* Media access controller */ + ETH_RESET_PHY = 1 << 6, /* Transceiver/PHY */ + ETH_RESET_RAM = 1 << 7, /* RAM shared between + * multiple components */ + + ETH_RESET_DEDICATED = 0x0000ffff, /* All components dedicated to + * this interface */ + ETH_RESET_ALL = 0xffffffff, /* All components used by this + * interface, even if shared */ +}; +#define ETH_RESET_SHARED_SHIFT 16 + #endif /* _LINUX_ETHTOOL_H */ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index e1951084b97..d8aee584e8d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -302,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 }; @@ -1089,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; } -- cgit v1.2.3 From 51953d5bc43e468f24cc573a45cde1d32af129b8 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Mon, 5 Oct 2009 08:24:16 +0000 Subject: Use sk_mark for IPv6 routing lookups Atis Elsts wrote: > Not sure if there is need to fill the mark from skb in tunnel xmit functions. In any case, it's not done for GRE or IPIP tunnels at the moment. Ok, I'll just drop that part, I'm not sure what should be done in this case. > Also, in this patch you are doing that for SIT (v6-in-v4) tunnels only, and not doing it for v4-in-v6 or v6-in-v6 tunnels. Any reason for that? I just sent that patch out too quickly, here's a better one with the updates. Add support for IPv6 route lookups using sk_mark. Signed-off-by: Brian Haley Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 1 + net/ipv6/datagram.c | 1 + net/ipv6/inet6_connection_sock.c | 1 + net/ipv6/ipv6_sockglue.c | 1 + net/ipv6/syncookies.c | 1 + net/ipv6/tcp_ipv6.c | 4 ++++ net/ipv6/udp.c | 2 ++ 7 files changed, 11 insertions(+) (limited to 'net') diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e127a32f954..da36497ae64 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -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..a615b4dea6c 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -147,6 +147,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; 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/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/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..321aafd40dc 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -243,6 +243,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 +384,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 +479,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); @@ -1345,6 +1348,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..3842c557d6f 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -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)); -- cgit v1.2.3 From f7734fdf61ec6bb848e0bafc1fb8bad2c124bb50 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 2 Oct 2009 11:39:15 +0000 Subject: make TLLAO option for NA packets configurable On Friday 02 October 2009 20:53:51 you wrote: > This is good although I would have shortened the name. Ah, I knew I forgot something :) Here is v4. tavi >From 24d96d825b9fa832b22878cc6c990d5711968734 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 2 Oct 2009 00:51:15 +0300 Subject: [PATCH] ipv6: new sysctl for sending TLLAO with unicast NAs Neighbor advertisements responding to unicast neighbor solicitations did not include the target link-layer address option. This patch adds a new sysctl option (disabled by default) which controls whether this option should be sent even with unicast NAs. The need for this arose because certain routers expect the TLLAO in some situations even as a response to unicast NS packets. Moreover, RFC 2461 recommends sending this to avoid a race condition (section 4.4, Target link-layer address) Signed-off-by: Cosmin Ratiu Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 18 ++++++++++++++++++ include/linux/ipv6.h | 1 + net/ipv6/addrconf.c | 8 ++++++++ net/ipv6/ndisc.c | 1 + 4 files changed, 28 insertions(+) (limited to 'net') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index fbe427a6580..a0e134dd252 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1086,6 +1086,24 @@ accept_dad - INTEGER 2: Enable DAD, and disable IPv6 operation if MAC-based duplicate link-local address has been found. +force_tllao - BOOLEAN + Enable sending the target link-layer address option even when + responding to a unicast neighbor solicitation. + Default: FALSE + + Quoting from RFC 2461, section 4.4, Target link-layer address: + + "The option MUST be included for multicast solicitations in order to + avoid infinite Neighbor Solicitation "recursion" when the peer node + does not have a cache entry to return a Neighbor Advertisements + message. When responding to unicast solicitations, the option can be + omitted since the sender of the solicitation has the correct link- + layer address; otherwise it would not have be able to send the unicast + solicitation in the first place. However, including the link-layer + address in this case adds little overhead and eliminates a potential + race condition where the sender deletes the cached link-layer address + prior to receiving a response to a previous solicitation." + icmp/*: ratelimit - INTEGER Limit the maximal rates for sending ICMPv6 packets. diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index c662efa6828..ae74ede1abe 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -167,6 +167,7 @@ struct ipv6_devconf { #endif __s32 disable_ipv6; __s32 accept_dad; + __s32 force_tllao; void *sysctl; }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1fd0a3d775d..bdcee6981c6 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4352,6 +4352,14 @@ static struct addrconf_sysctl_table .mode = 0644, .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/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); -- cgit v1.2.3 From ec1b4cf74c81bfd0fbe5bf62bafc86c45917e72f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 5 Oct 2009 05:58:39 +0000 Subject: net: mark net_proto_ops as const All usages of structure net_proto_ops should be declared const. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/isdn/mISDN/socket.c | 3 +-- drivers/net/pppox.c | 2 +- include/net/bluetooth/bluetooth.h | 2 +- net/appletalk/ddp.c | 2 +- net/atm/pvc.c | 2 +- net/atm/svc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/bluetooth/af_bluetooth.c | 4 ++-- net/bluetooth/bnep/sock.c | 2 +- net/bluetooth/cmtp/sock.c | 2 +- net/bluetooth/hci_sock.c | 2 +- net/bluetooth/hidp/sock.c | 2 +- net/bluetooth/l2cap.c | 2 +- net/bluetooth/rfcomm/sock.c | 2 +- net/bluetooth/sco.c | 2 +- net/can/af_can.c | 2 +- net/decnet/af_decnet.c | 2 +- net/econet/af_econet.c | 2 +- net/ieee802154/af_ieee802154.c | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipx/af_ipx.c | 2 +- net/irda/af_irda.c | 2 +- net/iucv/af_iucv.c | 2 +- net/key/af_key.c | 2 +- net/llc/af_llc.c | 2 +- net/netlink/af_netlink.c | 2 +- net/netrom/af_netrom.c | 2 +- net/packet/af_packet.c | 2 +- net/phonet/af_phonet.c | 2 +- net/rds/af_rds.c | 2 +- net/rose/af_rose.c | 2 +- net/rxrpc/af_rxrpc.c | 2 +- net/unix/af_unix.c | 2 +- net/x25/af_x25.c | 2 +- 35 files changed, 36 insertions(+), 37 deletions(-) (limited to 'net') diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index feb0fa45b66..28182ed8dea 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -808,8 +808,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto) return err; } -static struct -net_proto_family mISDN_sock_family_ops = { +static const struct net_proto_family mISDN_sock_family_ops = { .owner = THIS_MODULE, .family = PF_ISDN, .create = mISDN_sock_create, diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index 4f6d33fbc67..c14ee24c05a 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -125,7 +125,7 @@ out: return rc; } -static struct net_proto_family pppox_proto_family = { +static const struct net_proto_family pppox_proto_family = { .family = PF_PPPOX, .create = pppox_create, .owner = THIS_MODULE, diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 718394e2c01..04a6908e38d 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -121,7 +121,7 @@ struct bt_sock_list { rwlock_t lock; }; -int bt_sock_register(int proto, struct net_proto_family *ops); +int bt_sock_register(int proto, const struct net_proto_family *ops); int bt_sock_unregister(int proto); void bt_sock_link(struct bt_sock_list *l, struct sock *s); void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); 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/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..1f6e49c1cde 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; 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..c7078650385 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -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/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/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..6529be3a18b 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -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/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/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index da36497ae64..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, 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..c078ae6e975 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -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/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 efc1174af71..70073a0dea5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2399,7 +2399,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/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/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/x25/af_x25.c b/net/x25/af_x25.c index 7fa9c7ad3d3..ebbfe6bbbff 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -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, -- cgit v1.2.3 From 7c89606e24cdabaceb8ca9b3c7ab866c6bcc9e38 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 24 Sep 2009 12:21:01 +0200 Subject: nl80211: report age of scan results Linux keeps scan results up to 15 seconds. This can be a problem for fast moving clients: they get back stale data. But if the kernel reports the age of the BSS items, then user-space can simply weed out old entries by itself. Signed-off-by: Holger Schurig Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 2 ++ net/wireless/nl80211.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index a8d71ed43a0..50afca3dcff 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1277,6 +1277,7 @@ enum nl80211_channel_type { * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon * in unspecified units, scaled to 0..100 (u8) * @NL80211_BSS_STATUS: status, if this BSS is "used" + * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -1291,6 +1292,7 @@ enum nl80211_bss { NL80211_BSS_SIGNAL_MBM, NL80211_BSS_SIGNAL_UNSPEC, NL80211_BSS_STATUS, + NL80211_BSS_SEEN_MS_AGO, /* keep last */ __NL80211_BSS_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index eddab097435..e0ecc9f153d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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: -- cgit v1.2.3 From 3d23e349d807177eaf519d444677cee86b1a04cf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Sep 2009 23:27:28 +0200 Subject: wext: refactor Refactor wext to * split out iwpriv handling * split out iwspy handling * split out procfs support * allow cfg80211 to have wireless extensions compat code w/o CONFIG_WIRELESS_EXT After this, drivers need to - select WIRELESS_EXT - for wext support - select WEXT_PRIV - for iwpriv support - select WEXT_SPY - for iwspy support except cfg80211 -- which gets new hooks in wext-core.c and can then get wext handlers without CONFIG_WIRELESS_EXT. Wireless extensions procfs support is auto-selected based on PROC_FS and anything that requires the wext core (i.e. WIRELESS_EXT or CFG80211_WEXT). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 29 +- drivers/net/wireless/hostap/Kconfig | 2 + drivers/net/wireless/ipw2x00/Kconfig | 5 + drivers/net/wireless/orinoco/Kconfig | 2 + include/net/cfg80211.h | 6 +- include/net/iw_handler.h | 14 +- include/net/net_namespace.h | 2 +- include/net/wext.h | 49 +- net/core/net-sysfs.c | 6 +- net/socket.c | 4 +- net/wireless/Kconfig | 50 +- net/wireless/Makefile | 8 +- net/wireless/core.c | 14 +- net/wireless/ibss.c | 10 +- net/wireless/mlme.c | 2 +- net/wireless/nl80211.c | 4 +- net/wireless/scan.c | 6 +- net/wireless/sme.c | 12 +- net/wireless/wext-core.c | 1063 ++++++++++++++++++++ net/wireless/wext-priv.c | 248 +++++ net/wireless/wext-proc.c | 155 +++ net/wireless/wext-spy.c | 231 +++++ net/wireless/wext.c | 1775 ---------------------------------- 23 files changed, 1850 insertions(+), 1847 deletions(-) create mode 100644 net/wireless/wext-core.c create mode 100644 net/wireless/wext-priv.c create mode 100644 net/wireless/wext-proc.c create mode 100644 net/wireless/wext-spy.c delete mode 100644 net/wireless/wext.c (limited to 'net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index d7a764a2fc1..c9829c59fd9 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -67,6 +67,8 @@ config WAVELAN tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" depends on ISA && WLAN_PRE80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV ---help--- The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is a Radio LAN (wireless Ethernet-like Local Area Network) using the @@ -90,6 +92,8 @@ config PCMCIA_WAVELAN tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" depends on PCMCIA && WLAN_PRE80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV help Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA (PC-card) wireless Ethernet networking card to your computer. This @@ -102,6 +106,7 @@ config PCMCIA_NETWAVE tristate "Xircom Netwave AirSurfer Pcmcia wireless support" depends on PCMCIA && WLAN_PRE80211 select WIRELESS_EXT + select WEXT_PRIV help Say Y here if you intend to attach this type of PCMCIA (PC-card) wireless Ethernet networking card to your computer. @@ -123,6 +128,8 @@ config PCMCIA_RAYCS tristate "Aviator/Raytheon 2.4GHz wireless support" depends on PCMCIA && WLAN_80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV ---help--- Say Y here if you intend to attach an Aviator/Raytheon PCMCIA (PC-card) wireless Ethernet networking card to your computer. @@ -136,6 +143,7 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on WLAN_80211 select WIRELESS_EXT + select WEXT_SPY select LIB80211 select FW_LOADER ---help--- @@ -190,6 +198,8 @@ config AIRO depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) select WIRELESS_EXT select CRYPTO + select WEXT_SPY + select WEXT_PRIV ---help--- This is the standard Linux driver to support Cisco/Aironet ISA and PCI 802.11 wireless cards. @@ -207,6 +217,7 @@ config ATMEL tristate "Atmel at76c50x chipset 802.11b support" depends on (PCI || PCMCIA) && WLAN_80211 select WIRELESS_EXT + select WEXT_PRIV select FW_LOADER select CRC32 ---help--- @@ -266,18 +277,21 @@ config AIRO_CS Cisco Linux utilities can be used to configure the card. config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on EXPERIMENTAL && PCMCIA && WLAN_80211 - select WIRELESS_EXT - ---help--- - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. + tristate "Planet WL3501 PCMCIA cards" + depends on EXPERIMENTAL && PCMCIA && WLAN_80211 + select WIRELESS_EXT + select WEXT_SPY + help + A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. + It has basic support for Linux wireless extensions and initial + micro support for ethtool. config PRISM54 tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' depends on PCI && EXPERIMENTAL && WLAN_80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER ---help--- This enables support for FullMAC PCI/Cardbus prism54 devices. This @@ -300,6 +314,7 @@ config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" depends on USB && WLAN_80211 select WIRELESS_EXT + select WEXT_PRIV select FW_LOADER ---help--- Say Y if you want to use wireless LAN adapters based on the ZyDAS diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index c15db229351..08f1e989653 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -2,6 +2,8 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" depends on WLAN_80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select CRYPTO select CRYPTO_ARC4 select CRYPTO_ECB diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index a8131384c6b..56fab79dc36 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -6,6 +6,8 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER select LIB80211 select LIBIPW @@ -65,6 +67,8 @@ config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER select LIB80211 select LIBIPW @@ -152,6 +156,7 @@ config LIBIPW tristate depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT + select WEXT_SPY select CRYPTO select CRYPTO_ARC4 select CRYPTO_ECB diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 83b635fd778..13b03b3e8fc 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -3,6 +3,8 @@ config HERMES depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 depends on CFG80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER select CRYPTO select CRYPTO_MICHAEL_MIC diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3d874c62021..241ea14d6df 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1171,6 +1171,10 @@ struct wiphy { struct net *_net; #endif +#ifdef CONFIG_CFG80211_WEXT + const struct iw_handler_def *wext; +#endif + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; @@ -1345,7 +1349,7 @@ struct wireless_dev { struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; struct cfg80211_internal_bss *current_bss; /* associated / joined */ -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT /* wext data */ struct { struct cfg80211_ibss_params ibss; diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index e9054a283fd..d5d337170a5 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -323,18 +323,19 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, */ struct iw_handler_def { - /* Number of handlers defined (more precisely, index of the - * last defined handler + 1) */ - __u16 num_standard; - __u16 num_private; - /* Number of private arg description */ - __u16 num_private_args; /* Array of handlers for standard ioctls * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWCOMMIT] */ const iw_handler * standard; + /* Number of handlers defined (more precisely, index of the + * last defined handler + 1) */ + __u16 num_standard; +#ifdef CONFIG_WEXT_PRIV + __u16 num_private; + /* Number of private arg description */ + __u16 num_private_args; /* Array of handlers for private ioctls * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] */ @@ -344,6 +345,7 @@ struct iw_handler_def * can put it in any order you want and should not leave holes... * We will automatically export that to user space... */ const struct iw_priv_args * private_args; +#endif /* New location of get_wireless_stats, to de-bloat struct net_device. * The old pointer in struct net_device will be gradually phased diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index a1202841aad..699410142bf 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -80,7 +80,7 @@ struct net { #ifdef CONFIG_XFRM struct netns_xfrm xfrm; #endif -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; #endif struct net_generic *gen; diff --git a/include/net/wext.h b/include/net/wext.h index 3f2b94de2cf..4f6e7423174 100644 --- a/include/net/wext.h +++ b/include/net/wext.h @@ -1,29 +1,19 @@ #ifndef __NET_WEXT_H #define __NET_WEXT_H -/* - * wireless extensions interface to the core code - */ +#include struct net; -#ifdef CONFIG_WIRELESS_EXT -extern int wext_proc_init(struct net *net); -extern void wext_proc_exit(struct net *net); +#ifdef CONFIG_WEXT_CORE extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg); extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, unsigned long arg); + extern struct iw_statistics *get_wireless_stats(struct net_device *dev); +extern int call_commit_handler(struct net_device *dev); #else -static inline int wext_proc_init(struct net *net) -{ - return 0; -} -static inline void wext_proc_exit(struct net *net) -{ - return; -} static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg) { @@ -36,4 +26,35 @@ static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, } #endif +#ifdef CONFIG_WEXT_PROC +extern int wext_proc_init(struct net *net); +extern void wext_proc_exit(struct net *net); +#else +static inline int wext_proc_init(struct net *net) +{ + return 0; +} +static inline void wext_proc_exit(struct net *net) +{ + return; +} +#endif + +#ifdef CONFIG_WEXT_PRIV +int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler); +int compat_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler); +int iw_handler_get_private(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +#else +#define ioctl_private_call NULL +#define compat_private_call NULL +#endif + + #endif /* __NET_WEXT_H */ diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index effb78410eb..9b07535c288 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -543,8 +543,12 @@ 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 */ diff --git a/net/socket.c b/net/socket.c index 75655365b5f..92a56709fd7 100644 --- a/net/socket.c +++ b/net/socket.c @@ -905,11 +905,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: 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..c8141505a83 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-$(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 e6f02e98e5f..eb0bb24b99c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -358,6 +358,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; @@ -672,9 +676,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; @@ -696,7 +698,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; @@ -728,7 +730,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); @@ -766,7 +768,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/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 e0ecc9f153d..14004e2ebd6 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; 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-core.c b/net/wireless/wext-core.c new file mode 100644 index 00000000000..a4e5ddc8d4f --- /dev/null +++ b/net/wireless/wext-core.c @@ -0,0 +1,1063 @@ +/* + * This file implement the Wireless Extensions core API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * Copyright 2009 Johannes Berg + * + * (As all part of the Linux kernel, this file is GPL) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, + unsigned int, struct iw_request_info *, + iw_handler); + + +/* + * Meta-data about all the standard Wireless Extension request we + * know about. + */ +static const struct iw_ioctl_description standard_ioctl[] = { + [SIOCSIWCOMMIT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWNAME - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_CHAR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWNWID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWNWID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWFREQ - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWFREQ - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWMODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWMODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWSENS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWSENS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRANGE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWRANGE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_range), + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWPRIV - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_priv_args), + .max_tokens = 16, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWSTATS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_statistics), + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr), + .max_tokens = IW_MAX_SPY, + }, + [SIOCGIWSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_SPY, + }, + [SIOCSIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [SIOCGIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [SIOCSIWAP - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [SIOCGIWAP - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWMLME - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_mlme), + .max_tokens = sizeof(struct iw_mlme), + }, + [SIOCGIWAPLIST - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_AP, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWSCAN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = 0, + .max_tokens = sizeof(struct iw_scan_req), + }, + [SIOCGIWSCAN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_SCAN_MAX_DATA, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWESSID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWESSID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWNICKN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [SIOCGIWNICKN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [SIOCSIWRATE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRATE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRTS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRTS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWFRAG - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWFRAG - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWTXPOW - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWTXPOW - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRETRY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRETRY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWENCODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, + }, + [SIOCGIWENCODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, + }, + [SIOCSIWPOWER - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWPOWER - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWGENIE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [SIOCGIWGENIE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [SIOCSIWAUTH - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWAUTH - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWENCODEEXT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [SIOCGIWENCODEEXT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [SIOCSIWPMKSA - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_pmksa), + .max_tokens = sizeof(struct iw_pmksa), + }, +}; +static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); + +/* + * Meta-data about all the additional standard Wireless Extension events + * we know about. + */ +static const struct iw_ioctl_description standard_event[] = { + [IWEVTXDROP - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVQUAL - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_QUAL, + }, + [IWEVCUSTOM - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_CUSTOM_MAX, + }, + [IWEVREGISTERED - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVEXPIRED - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVGENIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVMICHAELMICFAILURE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_michaelmicfailure), + }, + [IWEVASSOCREQIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVASSOCRESPIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVPMKIDCAND - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_pmkid_cand), + }, +}; +static const unsigned standard_event_num = ARRAY_SIZE(standard_event); + +/* Size (in bytes) of various events */ +static const int event_type_size[] = { + IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_POINT_LEN, /* Without variable payload */ + IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; + +#ifdef CONFIG_COMPAT +static const int compat_event_type_size[] = { + IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ + IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; +#endif + + +/* IW event code */ + +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); + + + +/* IW handlers */ + +struct iw_statistics *get_wireless_stats(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 + +#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 + + /* not found */ + return NULL; +} + +static int iw_handler_get_iwstats(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + /* Get stats from the driver */ + struct iw_statistics *stats; + + 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); + + /* 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 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 */ + const struct iw_handler_def *handlers = NULL; + +#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 + + if (!handlers) + return NULL; + + /* Try as a standard command */ + index = cmd - SIOCIWFIRST; + if (index < handlers->num_standard) + return handlers->standard[index]; + +#ifdef CONFIG_WEXT_PRIV + /* Try as a private command */ + index = cmd - SIOCIWFIRSTPRIV; + if (index < handlers->num_private) + return handlers->private[index]; +#endif + + /* Not found */ + return NULL; +} + +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, + struct iw_request_info *info) +{ + int err, extra_size, user_length = 0, essid_compat = 0; + char *extra; + + /* Calculate space needed by arguments. Always allocate + * for max space. + */ + extra_size = descr->max_tokens * descr->token_size; + + /* Check need for ESSID compatibility for WE < 21 */ + switch (cmd) { + case SIOCSIWESSID: + case SIOCGIWESSID: + case SIOCSIWNICKN: + case SIOCGIWNICKN: + if (iwp->length == descr->max_tokens + 1) + essid_compat = 1; + else if (IW_IS_SET(cmd) && (iwp->length != 0)) { + char essid[IW_ESSID_MAX_SIZE + 1]; + unsigned int len; + len = iwp->length * descr->token_size; + + if (len > IW_ESSID_MAX_SIZE) + return -EFAULT; + + err = copy_from_user(essid, iwp->pointer, len); + if (err) + return -EFAULT; + + if (essid[iwp->length - 1] == '\0') + essid_compat = 1; + } + break; + default: + break; + } + + iwp->length -= essid_compat; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + /* Check NULL pointer */ + if (!iwp->pointer && iwp->length != 0) + return -EFAULT; + /* Check if number of token fits within bounds */ + if (iwp->length > descr->max_tokens) + return -E2BIG; + if (iwp->length < descr->min_tokens) + return -EINVAL; + } else { + /* Check NULL pointer */ + if (!iwp->pointer) + return -EFAULT; + /* Save user space buffer size for checking */ + user_length = iwp->length; + + /* Don't check if user_length > max to allow forward + * compatibility. The test user_length < min is + * implied by the test at the end. + */ + + /* Support for very large requests */ + if ((descr->flags & IW_DESCR_FLAG_NOMAX) && + (user_length > descr->max_tokens)) { + /* Allow userspace to GET more than max so + * we can support any size GET requests. + * There is still a limit : -ENOMEM. + */ + extra_size = user_length * descr->token_size; + + /* Note : user_length is originally a __u16, + * and token_size is controlled by us, + * so extra_size won't get negative and + * won't overflow... + */ + } + } + + /* kzalloc() ensures NULL-termination for essid_compat. */ + extra = kzalloc(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, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + + if (cmd == SIOCSIWENCODEEXT) { + struct iw_encode_ext *ee = (void *) extra; + + if (iwp->length < sizeof(*ee) + ee->key_len) + return -EFAULT; + } + } + + err = handler(dev, info, (union iwreq_data *) iwp, extra); + + iwp->length += essid_compat; + + /* If we have something to return to the user */ + if (!err && IW_IS_GET(cmd)) { + /* Check if there is enough buffer up there */ + if (user_length < iwp->length) { + err = -E2BIG; + goto out; + } + + if (copy_to_user(iwp->pointer, extra, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + } + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { + union iwreq_data *data = (union iwreq_data *) iwp; + + if (descr->flags & IW_DESCR_FLAG_RESTRICT) + /* If the event is restricted, don't + * export the payload. + */ + wireless_send_event(dev, cmd, data, NULL); + else + wireless_send_event(dev, cmd, data, extra); + } + +out: + kfree(extra); + return err; +} + +/* + * 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()" ;-) + */ +int call_commit_handler(struct net_device *dev) +{ +#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 +} + +/* + * Main IOCTl dispatcher. + * Check the type of IOCTL and call the appropriate wrapper... + */ +static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, + unsigned int cmd, + struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) +{ + struct iwreq *iwr = (struct iwreq *) ifr; + struct net_device *dev; + iw_handler handler; + + /* Permissions are already checked in dev_ioctl() before calling us. + * The copy_to/from_user() of ifr is also dealt with in there */ + + /* Make sure the device exist */ + if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) + return -ENODEV; + + /* A bunch of special cases, then the generic case... + * Note that 'cmd' is already filtered in dev_ioctl() with + * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ + if (cmd == SIOCGIWSTATS) + 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); +#endif + + /* Basic check */ + if (!netif_device_present(dev)) + return -ENODEV; + + /* New driver API : try to find the handler */ + handler = get_handler(dev, cmd); + if (handler) { + /* Standard and private are not the same */ + if (cmd < SIOCIWFIRSTPRIV) + return standard(dev, iwr, cmd, info, handler); + else if (private) + return private(dev, iwr, cmd, info, handler); + } + /* Old driver API : call driver ioctl handler */ + if (dev->netdev_ops->ndo_do_ioctl) + return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); + return -EOPNOTSUPP; +} + +/* If command is `set a parameter', or `get the encoding parameters', + * check if the user has the right to do it. + */ +static int wext_permission_check(unsigned int cmd) +{ + if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) + && !capable(CAP_NET_ADMIN)) + return -EPERM; + + return 0; +} + +/* entry point from dev ioctl */ +static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, + unsigned int cmd, struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) +{ + int ret = wext_permission_check(cmd); + + if (ret) + return ret; + + dev_load(net, ifr->ifr_name); + rtnl_lock(); + ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); + rtnl_unlock(); + + 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) +{ + struct iw_request_info info = { .cmd = cmd, .flags = 0 }; + int ret; + + ret = wext_ioctl_dispatch(net, ifr, cmd, &info, + ioctl_standard_call, + ioctl_private_call); + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(arg, ifr, sizeof(struct iwreq))) + return -EFAULT; + + return ret; +} + +#ifdef CONFIG_COMPAT +static int compat_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; + struct compat_iw_point *iwp_compat; + struct iw_point iwp; + int err; + + descr = standard_ioctl + (cmd - SIOCIWFIRST); + + if (descr->header_type != IW_HEADER_TYPE_POINT) + return ioctl_standard_call(dev, iwr, cmd, info, handler); + + 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; + + err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); + + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + + return err; +} + +int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct iw_request_info info; + struct iwreq iwr; + char *colon; + int ret; + + if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) + return -EFAULT; + + iwr.ifr_name[IFNAMSIZ-1] = 0; + colon = strchr(iwr.ifr_name, ':'); + if (colon) + *colon = 0; + + info.cmd = cmd; + info.flags = IW_REQUEST_FLAG_COMPAT; + + ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, + compat_standard_call, + compat_private_call); + + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(argp, &iwr, sizeof(struct iwreq))) + return -EFAULT; + + return ret; +} +#endif 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 - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * Copyright 2009 Johannes Berg + * + * (As all part of the Linux kernel, this file is GPL) + */ +#include +#include +#include +#include + +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 - + * 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 +#include +#include +#include +#include +#include +#include +#include + + +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 - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +#include +#include +#include +#include +#include +#include + +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/wireless/wext.c b/net/wireless/wext.c deleted file mode 100644 index 60fe57761ca..00000000000 --- a/net/wireless/wext.c +++ /dev/null @@ -1,1775 +0,0 @@ -/* - * This file implement the Wireless Extensions APIs. - * - * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. - * - * (As all part of the Linux kernel, this file is GPL) - */ - -/************************** DOCUMENTATION **************************/ -/* - * API definition : - * -------------- - * See 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 : - * 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 -#include /* off_t */ -#include /* struct ifreq, dev_get_by_name() */ -#include -#include /* rtnetlink stuff */ -#include -#include /* for __init */ -#include /* ARPHRD_ETHER */ -#include /* compare_ether_addr */ -#include -#include - -#include /* Pretty obvious */ -#include /* New driver API */ -#include -#include - -#include /* 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. - */ -static const struct iw_ioctl_description standard_ioctl[] = { - [SIOCSIWCOMMIT - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWNAME - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_CHAR, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWNWID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWNWID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWFREQ - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_FREQ, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWFREQ - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_FREQ, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWMODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_UINT, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWMODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_UINT, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWSENS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWSENS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWRANGE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWRANGE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_range), - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWPRIV - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct iw_priv_args), - .max_tokens = 16, - .flags = IW_DESCR_FLAG_NOMAX, - }, - [SIOCSIWSTATS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_statistics), - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct sockaddr), - .max_tokens = IW_MAX_SPY, - }, - [SIOCGIWSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct sockaddr) + - sizeof(struct iw_quality), - .max_tokens = IW_MAX_SPY, - }, - [SIOCSIWTHRSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct iw_thrspy), - .min_tokens = 1, - .max_tokens = 1, - }, - [SIOCGIWTHRSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct iw_thrspy), - .min_tokens = 1, - .max_tokens = 1, - }, - [SIOCSIWAP - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [SIOCGIWAP - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWMLME - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_mlme), - .max_tokens = sizeof(struct iw_mlme), - }, - [SIOCGIWAPLIST - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct sockaddr) + - sizeof(struct iw_quality), - .max_tokens = IW_MAX_AP, - .flags = IW_DESCR_FLAG_NOMAX, - }, - [SIOCSIWSCAN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = 0, - .max_tokens = sizeof(struct iw_scan_req), - }, - [SIOCGIWSCAN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_SCAN_MAX_DATA, - .flags = IW_DESCR_FLAG_NOMAX, - }, - [SIOCSIWESSID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWESSID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWNICKN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - }, - [SIOCGIWNICKN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - }, - [SIOCSIWRATE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWRATE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWRTS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWRTS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWFRAG - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWFRAG - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWTXPOW - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWTXPOW - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWRETRY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWRETRY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWENCODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ENCODING_TOKEN_MAX, - .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, - }, - [SIOCGIWENCODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ENCODING_TOKEN_MAX, - .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, - }, - [SIOCSIWPOWER - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWPOWER - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWGENIE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [SIOCGIWGENIE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [SIOCSIWAUTH - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWAUTH - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWENCODEEXT - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_encode_ext), - .max_tokens = sizeof(struct iw_encode_ext) + - IW_ENCODING_TOKEN_MAX, - }, - [SIOCGIWENCODEEXT - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_encode_ext), - .max_tokens = sizeof(struct iw_encode_ext) + - IW_ENCODING_TOKEN_MAX, - }, - [SIOCSIWPMKSA - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_pmksa), - .max_tokens = sizeof(struct iw_pmksa), - }, -}; -static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); - -/* - * Meta-data about all the additional standard Wireless Extension events - * we know about. - */ -static const struct iw_ioctl_description standard_event[] = { - [IWEVTXDROP - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [IWEVQUAL - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_QUAL, - }, - [IWEVCUSTOM - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_CUSTOM_MAX, - }, - [IWEVREGISTERED - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [IWEVEXPIRED - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [IWEVGENIE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [IWEVMICHAELMICFAILURE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_michaelmicfailure), - }, - [IWEVASSOCREQIE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [IWEVASSOCRESPIE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [IWEVPMKIDCAND - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_pmkid_cand), - }, -}; -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 */ - 0, - IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ - 0, - IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ - IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ - IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ - 0, - IW_EV_POINT_LEN, /* Without variable payload */ - IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ - IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ -}; - -#ifdef CONFIG_COMPAT -static const int compat_event_type_size[] = { - IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ - 0, - IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ - 0, - IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ - IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ - IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ - 0, - IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ - IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ - IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ -}; -#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]; - - /* Not found */ - return NULL; -} - -/* ---------------------------------------------------------------- */ -/* - * Get statistics out of the driver - */ -struct iw_statistics *get_wireless_stats(struct net_device *dev) -{ - /* 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; -} - -/* ---------------------------------------------------------------- */ -/* - * 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) -{ - 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 */ -} - -/* ---------------------------------------------------------------- */ -/* - * 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; - - return num * iw_priv_type_size[type]; -} - -/* ---------------------------------------------------------------- */ -/* - * Re-calculate the size of private arguments - */ -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]; -} - -/* ---------------------------------------------------------------- */ -/* - * 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) -{ - /* Get stats from the driver */ - struct iw_statistics *stats; - - 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); - - /* 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; -} - -/* ---------------------------------------------------------------- */ -/* - * Standard Wireless Handler : get iwpriv definitions - * Export the driver private handler definition - * They will be picked up by tools like iwpriv... - */ -static 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; -} - - -/******************** /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". - */ - -#ifdef CONFIG_PROC_FS - -/* ---------------------------------------------------------------- */ -/* - * 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 = {}; - - /* show device if it's wireless regardless of current stats */ - if (!stats && dev->wireless_handlers) - stats = &nullstats; - - 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"); -} -#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, - struct iw_request_info *info) -{ - int err, extra_size, user_length = 0, essid_compat = 0; - char *extra; - - /* Calculate space needed by arguments. Always allocate - * for max space. - */ - extra_size = descr->max_tokens * descr->token_size; - - /* Check need for ESSID compatibility for WE < 21 */ - switch (cmd) { - case SIOCSIWESSID: - case SIOCGIWESSID: - case SIOCSIWNICKN: - case SIOCGIWNICKN: - if (iwp->length == descr->max_tokens + 1) - essid_compat = 1; - else if (IW_IS_SET(cmd) && (iwp->length != 0)) { - char essid[IW_ESSID_MAX_SIZE + 1]; - unsigned int len; - len = iwp->length * descr->token_size; - - if (len > IW_ESSID_MAX_SIZE) - return -EFAULT; - - err = copy_from_user(essid, iwp->pointer, len); - if (err) - return -EFAULT; - - if (essid[iwp->length - 1] == '\0') - essid_compat = 1; - } - break; - default: - break; - } - - iwp->length -= essid_compat; - - /* Check what user space is giving us */ - if (IW_IS_SET(cmd)) { - /* Check NULL pointer */ - if (!iwp->pointer && iwp->length != 0) - return -EFAULT; - /* Check if number of token fits within bounds */ - if (iwp->length > descr->max_tokens) - return -E2BIG; - if (iwp->length < descr->min_tokens) - return -EINVAL; - } else { - /* Check NULL pointer */ - if (!iwp->pointer) - return -EFAULT; - /* Save user space buffer size for checking */ - user_length = iwp->length; - - /* Don't check if user_length > max to allow forward - * compatibility. The test user_length < min is - * implied by the test at the end. - */ - - /* Support for very large requests */ - if ((descr->flags & IW_DESCR_FLAG_NOMAX) && - (user_length > descr->max_tokens)) { - /* Allow userspace to GET more than max so - * we can support any size GET requests. - * There is still a limit : -ENOMEM. - */ - extra_size = user_length * descr->token_size; - - /* Note : user_length is originally a __u16, - * and token_size is controlled by us, - * so extra_size won't get negative and - * won't overflow... - */ - } - } - - /* kzalloc() ensures NULL-termination for essid_compat. */ - extra = kzalloc(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, - iwp->length * - descr->token_size)) { - err = -EFAULT; - goto out; - } - - if (cmd == SIOCSIWENCODEEXT) { - struct iw_encode_ext *ee = (void *) extra; - - if (iwp->length < sizeof(*ee) + ee->key_len) - return -EFAULT; - } - } - - err = handler(dev, info, (union iwreq_data *) iwp, extra); - - iwp->length += essid_compat; - - /* If we have something to return to the user */ - if (!err && IW_IS_GET(cmd)) { - /* Check if there is enough buffer up there */ - if (user_length < iwp->length) { - err = -E2BIG; - goto out; - } - - if (copy_to_user(iwp->pointer, extra, - iwp->length * - descr->token_size)) { - err = -EFAULT; - goto out; - } - } - - /* Generate an event to notify listeners of the change */ - if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { - union iwreq_data *data = (union iwreq_data *) iwp; - - if (descr->flags & IW_DESCR_FLAG_RESTRICT) - /* If the event is restricted, don't - * export the payload. - */ - wireless_send_event(dev, cmd, data, NULL); - else - wireless_send_event(dev, cmd, data, extra); - } - -out: - kfree(extra); - return err; -} - -/* - * 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. - * - * 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; -} - -static 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; -} - -/* ---------------------------------------------------------------- */ -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... - */ -static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, - unsigned int cmd, - struct iw_request_info *info, - wext_ioctl_func standard, - wext_ioctl_func private) -{ - struct iwreq *iwr = (struct iwreq *) ifr; - struct net_device *dev; - iw_handler handler; - - /* Permissions are already checked in dev_ioctl() before calling us. - * The copy_to/from_user() of ifr is also dealt with in there */ - - /* Make sure the device exist */ - if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) - return -ENODEV; - - /* A bunch of special cases, then the generic case... - * Note that 'cmd' is already filtered in dev_ioctl() with - * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ - if (cmd == SIOCGIWSTATS) - return standard(dev, iwr, cmd, info, - &iw_handler_get_iwstats); - - if (cmd == SIOCGIWPRIV && dev->wireless_handlers) - return standard(dev, iwr, cmd, info, - &iw_handler_get_private); - - /* Basic check */ - if (!netif_device_present(dev)) - return -ENODEV; - - /* New driver API : try to find the handler */ - handler = get_handler(dev, cmd); - if (handler) { - /* Standard and private are not the same */ - if (cmd < SIOCIWFIRSTPRIV) - return standard(dev, iwr, cmd, info, handler); - else - return private(dev, iwr, cmd, info, handler); - } - /* Old driver API : call driver ioctl handler */ - if (dev->netdev_ops->ndo_do_ioctl) - return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); - return -EOPNOTSUPP; -} - -/* If command is `set a parameter', or `get the encoding parameters', - * check if the user has the right to do it. - */ -static int wext_permission_check(unsigned int cmd) -{ - if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) - && !capable(CAP_NET_ADMIN)) - return -EPERM; - - return 0; -} - -/* entry point from dev ioctl */ -static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, - unsigned int cmd, struct iw_request_info *info, - wext_ioctl_func standard, - wext_ioctl_func private) -{ - int ret = wext_permission_check(cmd); - - if (ret) - return ret; - - dev_load(net, ifr->ifr_name); - rtnl_lock(); - ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); - rtnl_unlock(); - - return ret; -} - -int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, - void __user *arg) -{ - struct iw_request_info info = { .cmd = cmd, .flags = 0 }; - int ret; - - ret = wext_ioctl_dispatch(net, ifr, cmd, &info, - ioctl_standard_call, - ioctl_private_call); - if (ret >= 0 && - IW_IS_GET(cmd) && - copy_to_user(arg, ifr, sizeof(struct iwreq))) - return -EFAULT; - - return ret; -} - -#ifdef CONFIG_COMPAT -static int compat_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; - struct compat_iw_point *iwp_compat; - struct iw_point iwp; - int err; - - descr = standard_ioctl + (cmd - SIOCIWFIRST); - - if (descr->header_type != IW_HEADER_TYPE_POINT) - return ioctl_standard_call(dev, iwr, cmd, info, handler); - - 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; - - err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); - - iwp_compat->pointer = ptr_to_compat(iwp.pointer); - iwp_compat->length = iwp.length; - iwp_compat->flags = iwp.flags; - - 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) -{ - void __user *argp = (void __user *)arg; - struct iw_request_info info; - struct iwreq iwr; - char *colon; - int ret; - - if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) - return -EFAULT; - - iwr.ifr_name[IFNAMSIZ-1] = 0; - colon = strchr(iwr.ifr_name, ':'); - if (colon) - *colon = 0; - - info.cmd = cmd; - info.flags = IW_REQUEST_FLAG_COMPAT; - - ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, - compat_standard_call, - compat_private_call); - - if (ret >= 0 && - IW_IS_GET(cmd) && - copy_to_user(argp, &iwr, sizeof(struct iwreq))) - return -EFAULT; - - 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); -- cgit v1.2.3 From 4890e3beddfb4a6859c4bb782c9cd05dd94ead82 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 30 Sep 2009 14:50:17 -0400 Subject: wireless: implement basic ethtool support for cfg80211 devices Signed-off-by: John W. Linville --- net/wireless/Makefile | 2 +- net/wireless/core.c | 3 +++ net/wireless/ethtool.c | 24 ++++++++++++++++++++++++ net/wireless/ethtool.h | 8 ++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 net/wireless/ethtool.c create mode 100644 net/wireless/ethtool.h (limited to 'net') diff --git a/net/wireless/Makefile b/net/wireless/Makefile index c8141505a83..f07c8dc7aab 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -10,7 +10,7 @@ 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_CFG80211_WEXT) += wext-compat.o wext-sme.o diff --git a/net/wireless/core.c b/net/wireless/core.c index eb0bb24b99c..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" @@ -690,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) { diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c new file mode 100644 index 00000000000..80d6d0d31f1 --- /dev/null +++ b/net/wireless/ethtool.c @@ -0,0 +1,24 @@ +#include +#include +#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)); + + strlcpy(info->fw_version, "N/A", sizeof(info->fw_version)); + + strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), + sizeof(info->bus_info)); +} + +const struct ethtool_ops cfg80211_ethtool_ops = { + .get_drvinfo = cfg80211_get_drvinfo, + .get_link = ethtool_op_get_link, +}; diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h new file mode 100644 index 00000000000..70cbee1bc62 --- /dev/null +++ b/net/wireless/ethtool.h @@ -0,0 +1,8 @@ +#ifndef __CFG80211_ETHTOOL__ +#define __CFG80211_ETHTOOL__ + +#include + +extern const struct ethtool_ops cfg80211_ethtool_ops; + +#endif /* __CFG80211_ETHTOOL__ */ -- cgit v1.2.3 From dfce95f51fe34fa18c87a7d0bea53594b9bf1b9a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 24 Sep 2009 11:02:42 -0700 Subject: cfg80211: add firmware and hardware version to wiphy It's useful to provide firmware and hardware version to user space and have a generic interface to retrieve them. Users can provide the version information in bug reports etc. Add fields for firmware and hardware version to struct wiphy. (Dropped nl80211 bits for now and modified remaining bits in favor of ethtool. -- JWL) Cc: Kalle Valo Signed-off-by: John W. Linville --- include/net/cfg80211.h | 3 +++ net/wireless/ethtool.c | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 241ea14d6df..6f4862b3ec2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1142,6 +1142,9 @@ struct wiphy { u32 frag_threshold; u32 rts_threshold; + char fw_version[ETHTOOL_BUSINFO_LEN]; + u32 hw_version; + /* If multiple wiphys are registered and you're handed e.g. * a regular netdev with assigned ieee80211_ptr, you won't * know whether it points to a wiphy your driver has registered diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index 80d6d0d31f1..ca4c825be93 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c @@ -12,13 +12,34 @@ static void cfg80211_get_drvinfo(struct net_device *dev, strlcpy(info->version, init_utsname()->release, sizeof(info->version)); - strlcpy(info->fw_version, "N/A", sizeof(info->fw_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, }; -- cgit v1.2.3 From 0adc23f58e21cb47be998063ea1b82de33ccdd46 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 6 Oct 2009 16:27:18 -0400 Subject: mac80211: support ETHTOOL_GPERMADDR Signed-off-by: John W. Linville --- net/mac80211/iface.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f6005adcbf9..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); + } } /* @@ -784,6 +786,7 @@ 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)); /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ -- cgit v1.2.3 From a82ac21efcefabb4879eb5b4e7a2c7a142026bdb Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 7 Oct 2009 10:49:33 -0400 Subject: net/wireless/ethtool.h: drop unnecessary include of linux/ethtool.h Everything including this header includes net/cfg80211.h, which includes linux/netdevice.h, which includes linux/ethtool.h already. Why slow-down the build, even a little bit? Signed-off-by: John W. Linville --- net/wireless/ethtool.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h index 70cbee1bc62..695ecad20bd 100644 --- a/net/wireless/ethtool.h +++ b/net/wireless/ethtool.h @@ -1,8 +1,6 @@ #ifndef __CFG80211_ETHTOOL__ #define __CFG80211_ETHTOOL__ -#include - extern const struct ethtool_ops cfg80211_ethtool_ops; #endif /* __CFG80211_ETHTOOL__ */ -- cgit v1.2.3 From b1c00fe3cf8f54d97d20cdf196145a106f04bd63 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 5 Oct 2009 00:53:10 +0000 Subject: dccp ccid-2: Overhaul CCID naming convention 1/2 This patch starts a less problematic naming convention for CCID structs. The old naming convention used 'hc{tx,rx}->ccid?hc{tx,rx}->...' as recurring prefixes, which made the code * hard to write (not easy to fit into 80 characters); * hard to read (most of the space is occupied by prefixes). The new naming scheme: * struct entries for the TX socket are prefixed by 'tx_'; * and those for the RX socket are prefixed by 'rx_'. The identifiers then remain distinguishable when grep-ing through the tree: (a) RX/TX sockets are distinguished by the naming scheme, (b) individual CCIDs are distinguished by filename (ccid{2,3,4}.{c,h}). This first patch implements the scheme for CCID-2. Signed-off-by: Gerrit Renker Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 273 ++++++++++++++++++++++++------------------------- net/dccp/ccids/ccid2.h | 46 ++++----- 2 files changed, 158 insertions(+), 161 deletions(-) (limited to 'net') diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index e8cf99e880b..0675fd6215c 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -37,16 +37,16 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) { int len = 0; int pipe = 0; - struct ccid2_seq *seqp = hctx->ccid2hctx_seqh; + struct ccid2_seq *seqp = hctx->tx_seqh; /* there is data in the chain */ - if (seqp != hctx->ccid2hctx_seqt) { + if (seqp != hctx->tx_seqt) { seqp = seqp->ccid2s_prev; len++; if (!seqp->ccid2s_acked) pipe++; - while (seqp != hctx->ccid2hctx_seqt) { + while (seqp != hctx->tx_seqt) { struct ccid2_seq *prev = seqp->ccid2s_prev; len++; @@ -63,16 +63,16 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) } } - BUG_ON(pipe != hctx->ccid2hctx_pipe); + BUG_ON(pipe != hctx->tx_pipe); ccid2_pr_debug("len of chain=%d\n", len); do { seqp = seqp->ccid2s_prev; len++; - } while (seqp != hctx->ccid2hctx_seqh); + } while (seqp != hctx->tx_seqh); ccid2_pr_debug("total len=%d\n", len); - BUG_ON(len != hctx->ccid2hctx_seqbufc * CCID2_SEQBUF_LEN); + BUG_ON(len != hctx->tx_seqbufc * CCID2_SEQBUF_LEN); } #else #define ccid2_pr_debug(format, a...) @@ -85,8 +85,8 @@ static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx) 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 (hctx->tx_seqbufc >= (sizeof(hctx->tx_seqbuf) / + sizeof(struct ccid2_seq *))) return -ENOMEM; /* allocate buffer and initialize linked list */ @@ -102,20 +102,20 @@ 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 (hctx->tx_seqbufc == 0) + hctx->tx_seqh = hctx->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; + hctx->tx_seqh->ccid2s_next = seqp; + seqp->ccid2s_prev = hctx->tx_seqh; - hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1]; - seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hctx->ccid2hctx_seqt; + hctx->tx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1]; + seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hctx->tx_seqt; } /* store the original pointer to the buffer so we can free it */ - hctx->ccid2hctx_seqbuf[hctx->ccid2hctx_seqbufc] = seqp; - hctx->ccid2hctx_seqbufc++; + hctx->tx_seqbuf[hctx->tx_seqbufc] = seqp; + hctx->tx_seqbufc++; return 0; } @@ -124,7 +124,7 @@ 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); - if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd) + if (hctx->tx_pipe < hctx->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 @@ -158,7 +158,7 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hctx, long val) { ccid2_pr_debug("change SRTT to %ld\n", val); - hctx->ccid2hctx_srtt = val; + hctx->tx_srtt = val; } static void ccid2_start_rto_timer(struct sock *sk); @@ -171,8 +171,7 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) bh_lock_sock(sk); if (sock_owned_by_user(sk)) { - sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer, - jiffies + HZ / 5); + sk_reset_timer(sk, &hctx->tx_rtotimer, jiffies + HZ / 5); goto out; } @@ -181,28 +180,28 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) ccid2_hc_tx_check_sanity(hctx); /* back-off timer */ - hctx->ccid2hctx_rto <<= 1; + hctx->tx_rto <<= 1; - s = hctx->ccid2hctx_rto / HZ; + s = hctx->tx_rto / HZ; if (s > 60) - hctx->ccid2hctx_rto = 60 * HZ; + hctx->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; + hctx->tx_ssthresh = hctx->tx_cwnd / 2; + if (hctx->tx_ssthresh < 2) + hctx->tx_ssthresh = 2; + hctx->tx_cwnd = 1; + hctx->tx_pipe = 0; /* clear state about stuff we sent */ - hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh; - hctx->ccid2hctx_packets_acked = 0; + hctx->tx_seqt = hctx->tx_seqh; + hctx->tx_packets_acked = 0; /* clear ack ratio state. */ - hctx->ccid2hctx_rpseq = 0; - hctx->ccid2hctx_rpdupack = -1; + hctx->tx_rpseq = 0; + hctx->tx_rpdupack = -1; ccid2_change_l_ack_ratio(sk, 1); ccid2_hc_tx_check_sanity(hctx); out: @@ -214,11 +213,10 @@ static void ccid2_start_rto_timer(struct sock *sk) { struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); - ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto); + ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->tx_rto); - BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer)); - sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer, - jiffies + hctx->ccid2hctx_rto); + BUG_ON(timer_pending(&hctx->tx_rtotimer)); + sk_reset_timer(sk, &hctx->tx_rtotimer, jiffies + hctx->tx_rto); } static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) @@ -227,27 +225,26 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); struct ccid2_seq *next; - hctx->ccid2hctx_pipe++; + hctx->tx_pipe++; - hctx->ccid2hctx_seqh->ccid2s_seq = dp->dccps_gss; - hctx->ccid2hctx_seqh->ccid2s_acked = 0; - hctx->ccid2hctx_seqh->ccid2s_sent = jiffies; + hctx->tx_seqh->ccid2s_seq = dp->dccps_gss; + hctx->tx_seqh->ccid2s_acked = 0; + hctx->tx_seqh->ccid2s_sent = jiffies; - next = hctx->ccid2hctx_seqh->ccid2s_next; + next = hctx->tx_seqh->ccid2s_next; /* check if we need to alloc more space */ - if (next == hctx->ccid2hctx_seqt) { + if (next == hctx->tx_seqt) { if (ccid2_hc_tx_alloc_seq(hctx)) { 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 = hctx->tx_seqh->ccid2s_next; + BUG_ON(next == hctx->tx_seqt); } - hctx->ccid2hctx_seqh = next; + hctx->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", hctx->tx_cwnd, hctx->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++; + hctx->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 (hctx->tx_ackloss) { + if (hctx->tx_arsent >= hctx->tx_cwnd) { + hctx->tx_arsent = 0; + hctx->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 = hctx->tx_cwnd * hctx->tx_cwnd / denom; - if (hctx->ccid2hctx_arsent >= denom) { + if (hctx->tx_arsent >= denom) { ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1); - hctx->ccid2hctx_arsent = 0; + hctx->tx_arsent = 0; } } else { /* we can't increase ack ratio further [1] */ - hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/ + hctx->tx_arsent = 0; /* or maybe set it to cwnd*/ } } #endif /* setup RTO timer */ - if (!timer_pending(&hctx->ccid2hctx_rtotimer)) + if (!timer_pending(&hctx->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 = hctx->tx_seqt; - while (seqp != hctx->ccid2hctx_seqh) { + while (seqp != hctx->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); @@ -384,7 +381,7 @@ static void ccid2_hc_tx_kill_rto_timer(struct sock *sk) { struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); - sk_stop_timer(sk, &hctx->ccid2hctx_rtotimer); + sk_stop_timer(sk, &hctx->tx_rtotimer); ccid2_pr_debug("deleted RTO timer\n"); } @@ -394,73 +391,73 @@ static inline void ccid2_new_ack(struct sock *sk, { struct ccid2_hc_tx_sock *hctx = 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 (hctx->tx_cwnd < hctx->tx_ssthresh) { + if (*maxincr > 0 && ++hctx->tx_packets_acked == 2) { + hctx->tx_cwnd += 1; + *maxincr -= 1; + hctx->tx_packets_acked = 0; } - } else if (++hctx->ccid2hctx_packets_acked >= hctx->ccid2hctx_cwnd) { - hctx->ccid2hctx_cwnd += 1; - hctx->ccid2hctx_packets_acked = 0; + } else if (++hctx->tx_packets_acked >= hctx->tx_cwnd) { + hctx->tx_cwnd += 1; + hctx->tx_packets_acked = 0; } /* update RTO */ - if (hctx->ccid2hctx_srtt == -1 || - time_after(jiffies, hctx->ccid2hctx_lastrtt + hctx->ccid2hctx_srtt)) { + if (hctx->tx_srtt == -1 || + time_after(jiffies, hctx->tx_lastrtt + hctx->tx_srtt)) { unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent; int s; /* first measurement */ - if (hctx->ccid2hctx_srtt == -1) { + if (hctx->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; + hctx->tx_rttvar = r >> 1; } else { /* RTTVAR */ - long tmp = hctx->ccid2hctx_srtt - r; + long tmp = hctx->tx_srtt - r; long srtt; if (tmp < 0) tmp *= -1; tmp >>= 2; - hctx->ccid2hctx_rttvar *= 3; - hctx->ccid2hctx_rttvar >>= 2; - hctx->ccid2hctx_rttvar += tmp; + hctx->tx_rttvar *= 3; + hctx->tx_rttvar >>= 2; + hctx->tx_rttvar += tmp; /* SRTT */ - srtt = hctx->ccid2hctx_srtt; + srtt = hctx->tx_srtt; srtt *= 7; srtt >>= 3; tmp = r >> 3; srtt += tmp; ccid2_change_srtt(hctx, srtt); } - s = hctx->ccid2hctx_rttvar << 2; + s = hctx->tx_rttvar << 2; /* clock granularity is 1 when based on jiffies */ if (!s) s = 1; - hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s; + hctx->tx_rto = hctx->tx_srtt + s; /* must be at least a second */ - s = hctx->ccid2hctx_rto / HZ; + s = hctx->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; + hctx->tx_rto = HZ; #endif /* max 60 seconds */ if (s > 60) - hctx->ccid2hctx_rto = HZ * 60; + hctx->tx_rto = HZ * 60; - hctx->ccid2hctx_lastrtt = jiffies; + hctx->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); + hctx->tx_srtt, hctx->tx_rttvar, + hctx->tx_rto, HZ, r); } /* we got a new ack, so re-start RTO timer */ @@ -472,12 +469,12 @@ static void ccid2_hc_tx_dec_pipe(struct sock *sk) { struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); - if (hctx->ccid2hctx_pipe == 0) + if (hctx->tx_pipe == 0) DCCP_BUG("pipe == 0"); else - hctx->ccid2hctx_pipe--; + hctx->tx_pipe--; - if (hctx->ccid2hctx_pipe == 0) + if (hctx->tx_pipe == 0) ccid2_hc_tx_kill_rto_timer(sk); } @@ -485,19 +482,19 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp) { struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); - if (time_before(seqp->ccid2s_sent, hctx->ccid2hctx_last_cong)) { + if (time_before(seqp->ccid2s_sent, hctx->tx_last_cong)) { ccid2_pr_debug("Multiple losses in an RTT---treating as one\n"); return; } - hctx->ccid2hctx_last_cong = jiffies; + hctx->tx_last_cong = jiffies; - hctx->ccid2hctx_cwnd = hctx->ccid2hctx_cwnd / 2 ? : 1U; - hctx->ccid2hctx_ssthresh = max(hctx->ccid2hctx_cwnd, 2U); + hctx->tx_cwnd = hctx->tx_cwnd / 2 ? : 1U; + hctx->tx_ssthresh = max(hctx->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 > hctx->tx_cwnd) + ccid2_change_l_ack_ratio(sk, hctx->tx_cwnd); } static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) @@ -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 (hctx->tx_rpdupack == -1) { + hctx->tx_rpdupack = 0; + hctx->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(hctx->tx_rpseq, seqno) == 1) + hctx->tx_rpseq = seqno; /* it's a later packet */ - else if (after48(seqno, hctx->ccid2hctx_rpseq)) { - hctx->ccid2hctx_rpdupack++; + else if (after48(seqno, hctx->tx_rpseq)) { + hctx->tx_rpdupack++; /* check if we got enough dupacks */ - if (hctx->ccid2hctx_rpdupack >= NUMDUPACK) { - hctx->ccid2hctx_rpdupack = -1; /* XXX lame */ - hctx->ccid2hctx_rpseq = 0; + if (hctx->tx_rpdupack >= NUMDUPACK) { + hctx->tx_rpdupack = -1; /* XXX lame */ + hctx->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 (hctx->tx_seqh == hctx->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, hctx->tx_high_ack)) + hctx->tx_high_ack = ackno; - seqp = hctx->ccid2hctx_seqt; + seqp = hctx->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 == hctx->tx_seqh) { + seqp = hctx->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 (hctx->tx_cwnd < hctx->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 == hctx->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 == hctx->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 = hctx->tx_seqt; + while (before48(seqp->ccid2s_seq, hctx->tx_high_ack)) { seqp = seqp->ccid2s_next; - if (seqp == hctx->ccid2hctx_seqh) { - seqp = hctx->ccid2hctx_seqh->ccid2s_prev; + if (seqp == hctx->tx_seqh) { + seqp = hctx->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 == hctx->tx_seqt) break; seqp = seqp->ccid2s_prev; } @@ -681,20 +678,20 @@ 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 == hctx->tx_seqt) break; seqp = seqp->ccid2s_prev; } - hctx->ccid2hctx_seqt = last_acked; + hctx->tx_seqt = last_acked; } /* trim acked packets in tail */ - while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) { - if (!hctx->ccid2hctx_seqt->ccid2s_acked) + while (hctx->tx_seqt != hctx->tx_seqh) { + if (!hctx->tx_seqt->ccid2s_acked) break; - hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next; + hctx->tx_seqt = hctx->tx_seqt->ccid2s_next; } ccid2_hc_tx_check_sanity(hctx); @@ -707,17 +704,17 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) u32 max_ratio; /* RFC 4341, 5: initialise ssthresh to arbitrarily high (max) value */ - hctx->ccid2hctx_ssthresh = ~0U; + hctx->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); + hctx->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(hctx->tx_cwnd, 2); if (dp->dccps_l_ack_ratio == 0 || dp->dccps_l_ack_ratio > max_ratio) dp->dccps_l_ack_ratio = max_ratio; @@ -725,12 +722,12 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) if (ccid2_hc_tx_alloc_seq(hctx)) return -ENOMEM; - hctx->ccid2hctx_rto = 3 * HZ; + hctx->tx_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, + hctx->tx_rttvar = -1; + hctx->tx_rpdupack = -1; + hctx->tx_last_cong = jiffies; + setup_timer(&hctx->tx_rtotimer, ccid2_hc_tx_rto_expire, (unsigned long)sk); ccid2_hc_tx_check_sanity(hctx); @@ -744,9 +741,9 @@ static void ccid2_hc_tx_exit(struct sock *sk) 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 < hctx->tx_seqbufc; i++) + kfree(hctx->tx_seqbuf[i]); + hctx->tx_seqbufc = 0; } static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) @@ -757,10 +754,10 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) 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) { + hcrx->rx_data++; + if (hcrx->rx_data >= dp->dccps_r_ack_ratio) { dccp_send_ack(sk); - hcrx->ccid2hcrx_data = 0; + hcrx->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) -- cgit v1.2.3 From 388d5e9905dd80648fff5ccaefdd8c0fcedb3eae Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 5 Oct 2009 00:53:11 +0000 Subject: dccp ccid-3: Overhaul CCID naming convention 2/2 This implements the new naming scheme also for CCID-3. Signed-off-by: Gerrit Renker Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 321 +++++++++++++++++++++++-------------------------- net/dccp/ccids/ccid3.h | 120 +++++++++--------- net/dccp/probe.c | 10 +- 3 files changed, 213 insertions(+), 238 deletions(-) (limited to 'net') diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 34dcc798c45..6b8d67ba7fe 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -65,13 +65,13 @@ 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; + enum ccid3_hc_tx_states oldstate = hctx->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; + hctx->tx_state = state; } /* @@ -86,10 +86,9 @@ 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 __u32 w_init = clamp_t(__u32, 4380U, 2 * hctx->tx_s, 4 * hctx->tx_s); - return scaled_div(w_init << 6, hctx->ccid3hctx_rtt); + return scaled_div(w_init << 6, hctx->tx_rtt); } /* @@ -98,24 +97,20 @@ static inline u64 rfc3390_initial_rate(struct sock *sk) static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hctx) { /* 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); + hctx->tx_t_ipi = scaled_div32(((u64)hctx->tx_s) << 6, hctx->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)); + hctx->tx_delta = min_t(u32, hctx->tx_t_ipi / 2, TFRC_OPSYS_HALF_TIME_GRAN); + ccid3_pr_debug("t_ipi=%u, delta=%u, s=%u, X=%u\n", hctx->tx_t_ipi, + hctx->tx_delta, hctx->tx_s, (unsigned)(hctx->tx_x >> 6)); } static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hctx, ktime_t now) { - u32 delta = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count); + u32 delta = ktime_us_delta(now, hctx->tx_t_last_win_count); - return delta / hctx->ccid3hctx_rtt; + return delta / hctx->tx_rtt; } /** @@ -131,8 +126,8 @@ 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; + __u64 min_rate = 2 * hctx->tx_x_recv; + const __u64 old_x = hctx->tx_x; ktime_t now = stamp ? *stamp : ktime_get_real(); /* @@ -143,33 +138,27 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp) */ if (ccid3_hc_tx_idle_rtt(hctx, now) >= 2) { min_rate = rfc3390_initial_rate(sk); - min_rate = max(min_rate, 2 * hctx->ccid3hctx_x_recv); + min_rate = max(min_rate, 2 * hctx->tx_x_recv); } - if (hctx->ccid3hctx_p > 0) { + if (hctx->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); + hctx->tx_x = min(((__u64)hctx->tx_x_calc) << 6, min_rate); + hctx->tx_x = max(hctx->tx_x, (((__u64)hctx->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, hctx->tx_t_ld) - (s64)hctx->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; + hctx->tx_x = min(2 * hctx->tx_x, min_rate); + hctx->tx_x = max(hctx->tx_x, scaled_div(((__u64)hctx->tx_s) << 6, + hctx->tx_rtt)); + hctx->tx_t_ld = now; } - if (hctx->ccid3hctx_x != old_x) { + if (hctx->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)(hctx->tx_x >> 6), hctx->tx_x_calc, + (unsigned)(hctx->tx_x_recv >> 6)); ccid3_update_send_interval(hctx); } @@ -181,11 +170,11 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp) */ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) { - const u16 old_s = hctx->ccid3hctx_s; + const u16 old_s = hctx->tx_s; - hctx->ccid3hctx_s = tfrc_ewma(hctx->ccid3hctx_s, len, 9); + hctx->tx_s = tfrc_ewma(hctx->tx_s, len, 9); - if (hctx->ccid3hctx_s != old_s) + if (hctx->tx_s != old_s) ccid3_update_send_interval(hctx); } @@ -196,13 +185,13 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx, 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, hctx->tx_t_last_win_count), + quarter_rtts = (4 * delta) / hctx->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 */ + hctx->tx_t_last_win_count = now; + hctx->tx_last_win_count += min(quarter_rtts, 5U); + hctx->tx_last_win_count &= 0xF; /* mod 16 */ } } @@ -220,23 +209,22 @@ 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(hctx->tx_state)); - if (hctx->ccid3hctx_state == TFRC_SSTATE_FBACK) + if (hctx->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 (hctx->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 (hctx->tx_t_rto == 0 || /* no feedback received yet */ + hctx->tx_p == 0) { /* halve send rate directly */ - hctx->ccid3hctx_x = max(hctx->ccid3hctx_x / 2, - (((__u64)hctx->ccid3hctx_s) << 6) / - TFRC_T_MBI); + hctx->tx_x = max(hctx->tx_x / 2, + (((__u64)hctx->tx_s) << 6) / TFRC_T_MBI); ccid3_update_send_interval(hctx); } else { /* @@ -249,33 +237,33 @@ 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(hctx->tx_p && !hctx->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) / + if (hctx->tx_x_calc > (hctx->tx_x_recv >> 5)) + hctx->tx_x_recv = + max(hctx->tx_x_recv / 2, + (((__u64)hctx->tx_s) << 6) / (2 * TFRC_T_MBI)); else { - hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc; - hctx->ccid3hctx_x_recv <<= 4; + hctx->tx_x_recv = hctx->tx_x_calc; + hctx->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)hctx->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(hctx->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(hctx->tx_t_rto, 2 * hctx->tx_t_ipi); restart_timer: - sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, + sk_reset_timer(sk, &hctx->tx_no_feedback_timer, jiffies + usecs_to_jiffies(t_nfb)); out: bh_unlock_sock(sk); @@ -303,18 +291,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 (hctx->tx_state) { case TFRC_SSTATE_NO_SENT: - sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, - (jiffies + + sk_reset_timer(sk, &hctx->tx_no_feedback_timer, (jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT))); - hctx->ccid3hctx_last_win_count = 0; - hctx->ccid3hctx_t_last_win_count = now; + hctx->tx_last_win_count = 0; + hctx->tx_t_last_win_count = now; /* Set t_0 for initial packet */ - hctx->ccid3hctx_t_nom = now; + hctx->tx_t_nom = now; - hctx->ccid3hctx_s = skb->len; + hctx->tx_s = skb->len; /* * Use initial RTT sample when available: recommended by erratum @@ -323,9 +310,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; + hctx->tx_rtt = dp->dccps_syn_rtt; + hctx->tx_x = rfc3390_initial_rate(sk); + hctx->tx_t_ld = now; } else { /* * Sender does not have RTT sample: @@ -333,9 +320,9 @@ 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; + hctx->tx_rtt = DCCP_FALLBACK_RTT; + hctx->tx_x = hctx->tx_s; + hctx->tx_x <<= 6; } ccid3_update_send_interval(hctx); @@ -343,7 +330,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) break; case TFRC_SSTATE_NO_FBACK: case TFRC_SSTATE_FBACK: - delay = ktime_us_delta(hctx->ccid3hctx_t_nom, now); + delay = ktime_us_delta(hctx->tx_t_nom, now); ccid3_pr_debug("delay=%ld\n", (long)delay); /* * Scheduling of packet transmissions [RFC 3448, 4.6] @@ -353,7 +340,7 @@ 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)hctx->tx_delta >= 1000) return (u32)delay / 1000L; ccid3_hc_tx_update_win_count(hctx, now); @@ -365,11 +352,10 @@ 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 = hctx->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); + hctx->tx_t_nom = ktime_add_us(hctx->tx_t_nom, hctx->tx_t_ipi); return 0; } @@ -380,7 +366,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, ccid3_hc_tx_update_s(hctx, len); - if (tfrc_tx_hist_add(&hctx->ccid3hctx_hist, dccp_sk(sk)->dccps_gss)) + if (tfrc_tx_hist_add(&hctx->tx_hist, dccp_sk(sk)->dccps_gss)) DCCP_CRIT("packet history - out of memory!"); } @@ -397,15 +383,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 (hctx->tx_state != TFRC_SSTATE_FBACK && + hctx->tx_state != TFRC_SSTATE_NO_FBACK) return; - opt_recv = &hctx->ccid3hctx_options_received; + opt_recv = &hctx->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(hctx->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 +401,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; + hctx->tx_x_recv = opt_recv->ccid3or_receive_rate; + hctx->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; + hctx->tx_p = 0; else /* can not exceed 100% */ - hctx->ccid3hctx_p = scaled_div(1, pinv); + hctx->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); + hctx->tx_rtt = tfrc_ewma(hctx->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 (hctx->tx_state == TFRC_SSTATE_NO_FBACK) { ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); - if (hctx->ccid3hctx_t_rto == 0) { + if (hctx->tx_t_rto == 0) { /* * Initial feedback packet: Larger Initial Windows (4.2) */ - hctx->ccid3hctx_x = rfc3390_initial_rate(sk); - hctx->ccid3hctx_t_ld = now; + hctx->tx_x = rfc3390_initial_rate(sk); + hctx->tx_t_ld = now; ccid3_update_send_interval(hctx); goto done_computing_x; - } else if (hctx->ccid3hctx_p == 0) { + } else if (hctx->tx_p == 0) { /* * First feedback after nofeedback timer expiry (4.3) */ @@ -454,25 +440,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 (hctx->tx_p > 0) + hctx->tx_x_calc = tfrc_calc_x(hctx->tx_s, hctx->tx_rtt, hctx->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, hctx->tx_rtt, r_sample, + hctx->tx_s, hctx->tx_p, hctx->tx_x_calc, + (unsigned)(hctx->tx_x_recv >> 6), + (unsigned)(hctx->tx_x >> 6)); /* unschedule no feedback timer */ - sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); + sk_stop_timer(sk, &hctx->tx_no_feedback_timer); /* * As we have calculated new ipi, delta, t_nom it is possible @@ -486,21 +467,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))); + hctx->tx_t_rto = max_t(u32, 4 * hctx->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(hctx->tx_t_rto, 2 * hctx->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, &hctx->tx_no_feedback_timer, jiffies + usecs_to_jiffies(t_nfb)); } @@ -514,7 +493,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, struct ccid3_options_received *opt_recv; __be32 opt_val; - opt_recv = &hctx->ccid3hctx_options_received; + opt_recv = &hctx->tx_options_received; if (opt_recv->ccid3or_seqno != dp->dccps_gsr) { opt_recv->ccid3or_seqno = dp->dccps_gsr; @@ -570,11 +549,10 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) { struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid); - hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT; - hctx->ccid3hctx_hist = NULL; - setup_timer(&hctx->ccid3hctx_no_feedback_timer, + hctx->tx_state = TFRC_SSTATE_NO_SENT; + hctx->tx_hist = NULL; + setup_timer(&hctx->tx_no_feedback_timer, ccid3_hc_tx_no_feedback_timer, (unsigned long)sk); - return 0; } @@ -583,9 +561,9 @@ static void ccid3_hc_tx_exit(struct sock *sk) struct ccid3_hc_tx_sock *hctx = 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, &hctx->tx_no_feedback_timer); - tfrc_tx_hist_purge(&hctx->ccid3hctx_hist); + tfrc_tx_hist_purge(&hctx->tx_hist); } static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) @@ -597,8 +575,8 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) return; hctx = ccid3_hc_tx_sk(sk); - info->tcpi_rto = hctx->ccid3hctx_t_rto; - info->tcpi_rtt = hctx->ccid3hctx_rtt; + info->tcpi_rto = hctx->tx_t_rto; + info->tcpi_rtt = hctx->tx_rtt; } static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, @@ -614,10 +592,10 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, hctx = ccid3_hc_tx_sk(sk); switch (optname) { case DCCP_SOCKOPT_CCID_TX_INFO: - if (len < sizeof(hctx->ccid3hctx_tfrc)) + if (len < sizeof(hctx->tx_tfrc)) return -EINVAL; - len = sizeof(hctx->ccid3hctx_tfrc); - val = &hctx->ccid3hctx_tfrc; + len = sizeof(hctx->tx_tfrc); + val = &hctx->tx_tfrc; break; default: return -ENOPROTOOPT; @@ -658,13 +636,13 @@ 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; + enum ccid3_hc_rx_states oldstate = hcrx->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; + hcrx->rx_state = state; } static void ccid3_hc_rx_send_feedback(struct sock *sk, @@ -676,15 +654,15 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk, ktime_t now; s64 delta = 0; - if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_TERM)) + if (unlikely(hcrx->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 */ + hcrx->rx_x_recv = 0; + hcrx->rx_pinv = ~0U; /* see RFC 4342, 8.5 */ break; case CCID3_FBACK_PARAM_CHANGE: /* @@ -697,27 +675,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 (hcrx->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, hcrx->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); + hcrx->rx_x_recv = scaled_div32(hcrx->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); + hcrx->rx_x_recv, hcrx->rx_pinv); - hcrx->ccid3hcrx_tstamp_last_feedback = now; - hcrx->ccid3hcrx_last_counter = dccp_hdr(skb)->dccph_ccval; - hcrx->ccid3hcrx_bytes_recv = 0; + hcrx->rx_tstamp_last_feedback = now; + hcrx->rx_last_counter = dccp_hdr(skb)->dccph_ccval; + hcrx->rx_bytes_recv = 0; dp->dccps_hc_rx_insert_options = 1; dccp_send_ack(sk); @@ -736,8 +713,8 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) if (dccp_packet_without_ack(skb)) return 0; - x_recv = htonl(hcrx->ccid3hcrx_x_recv); - pinv = htonl(hcrx->ccid3hcrx_pinv); + x_recv = htonl(hcrx->rx_x_recv); + pinv = htonl(hcrx->rx_pinv); if (dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE, &pinv, sizeof(pinv)) || @@ -764,22 +741,22 @@ static u32 ccid3_first_li(struct sock *sk) u32 x_recv, p, delta; u64 fval; - if (hcrx->ccid3hcrx_rtt == 0) { + if (hcrx->rx_rtt == 0) { DCCP_WARN("No RTT estimate available, using fallback RTT\n"); - hcrx->ccid3hcrx_rtt = DCCP_FALLBACK_RTT; + hcrx->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(hcrx->rx_tstamp_last_feedback)); + x_recv = scaled_div32(hcrx->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 = hcrx->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(hcrx->rx_s, hcrx->rx_rtt); fval = scaled_div32(fval, x_recv); p = tfrc_calc_x_reverse_lookup(fval); @@ -796,14 +773,14 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) 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(hcrx->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; + hcrx->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 +788,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(&hcrx->rx_hist, skb)) return; /* done receiving */ if (is_data_packet) { @@ -819,20 +796,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; + hcrx->rx_s = tfrc_ewma(hcrx->rx_s, payload, 9); + hcrx->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(&hcrx->rx_hist, &hcrx->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(&hcrx->rx_hist)) return; /* done receiving */ /* @@ -841,17 +818,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(&hcrx->rx_li_hist)) { + const u32 sample = tfrc_rx_hist_sample_rtt(&hcrx->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); + hcrx->rx_rtt = tfrc_ewma(hcrx->rx_rtt, sample, 9); - } else if (tfrc_lh_update_i_mean(&hcrx->ccid3hcrx_li_hist, skb)) { + } else if (tfrc_lh_update_i_mean(&hcrx->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 +839,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, hcrx->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(&hcrx->rx_hist, skb, ndp); done_receiving: if (do_feedback) @@ -877,9 +854,9 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk) { struct ccid3_hc_rx_sock *hcrx = 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); + hcrx->rx_state = TFRC_RSTATE_NO_DATA; + tfrc_lh_init(&hcrx->rx_li_hist); + return tfrc_rx_hist_alloc(&hcrx->rx_hist); } static void ccid3_hc_rx_exit(struct sock *sk) @@ -888,8 +865,8 @@ static void ccid3_hc_rx_exit(struct sock *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(&hcrx->rx_hist); + tfrc_lh_cleanup(&hcrx->rx_li_hist); } static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) @@ -901,9 +878,9 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) return; hcrx = ccid3_hc_rx_sk(sk); - info->tcpi_ca_state = hcrx->ccid3hcrx_state; + info->tcpi_ca_state = hcrx->rx_state; info->tcpi_options |= TCPI_OPT_TIMESTAMPS; - info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt; + info->tcpi_rcv_rtt = hcrx->rx_rtt; } static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len, @@ -922,10 +899,10 @@ static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len, 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 = hcrx->rx_x_recv; + rx_info.tfrcrx_rtt = hcrx->rx_rtt; + rx_info.tfrcrx_p = hcrx->rx_pinv == 0 ? ~0U : + scaled_div(1, hcrx->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/probe.c b/net/dccp/probe.c index 37731da4148..430d16fd6f5 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -83,14 +83,12 @@ static int jdccp_sendmsg(struct kiocb *iocb, struct sock *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", + 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); + hctx->tx_s, hctx->tx_rtt, hctx->tx_p, + hctx->tx_x_calc, hctx->tx_x_recv >> 6, + hctx->tx_x >> 6, hctx->tx_t_ipi); else printl("%pI4:%u %pI4:%u %d\n", &inet->saddr, ntohs(inet->sport), -- cgit v1.2.3 From 77d2dd93742222973d253443d98ab8402d641038 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 5 Oct 2009 00:53:12 +0000 Subject: dccp ccid-2: Remove CCID naming redundancy 1/2 This removes a redundancy in the CCID half-connection (hc) naming scheme: * instead of 'hctx->tx_...', write 'hc->tx_...'; * instead of 'hcrx->rx_...', write 'hc->rx_...'; which works because the 'type' of the half-connection is encoded in the 'rx_' / 'tx_' prefixes. Signed-off-by: Gerrit Renker Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid2.c | 322 ++++++++++++++++++++++++------------------------- 1 file changed, 161 insertions(+), 161 deletions(-) (limited to 'net') diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 0675fd6215c..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->tx_seqh; + struct ccid2_seq *seqp = hc->tx_seqh; /* there is data in the chain */ - if (seqp != hctx->tx_seqt) { + if (seqp != hc->tx_seqt) { seqp = seqp->ccid2s_prev; len++; if (!seqp->ccid2s_acked) pipe++; - while (seqp != hctx->tx_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->tx_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->tx_seqh); + } while (seqp != hc->tx_seqh); ccid2_pr_debug("total len=%d\n", len); - BUG_ON(len != hctx->tx_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->tx_seqbufc >= (sizeof(hctx->tx_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->tx_seqbufc == 0) - hctx->tx_seqh = hctx->tx_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->tx_seqh->ccid2s_next = seqp; - seqp->ccid2s_prev = hctx->tx_seqh; + hc->tx_seqh->ccid2s_next = seqp; + seqp->ccid2s_prev = hc->tx_seqh; - hctx->tx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1]; - seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hctx->tx_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->tx_seqbuf[hctx->tx_seqbufc] = seqp; - hctx->tx_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->tx_pipe < hctx->tx_cwnd) + if (hc->tx_pipe < hc->tx_cwnd) return 0; return 1; /* XXX CCID should dequeue when ready instead of polling */ @@ -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->tx_srtt = val; + hc->tx_srtt = val; } static void ccid2_start_rto_timer(struct sock *sk); @@ -166,44 +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->tx_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->tx_rto <<= 1; + hc->tx_rto <<= 1; - s = hctx->tx_rto / HZ; + s = hc->tx_rto / HZ; if (s > 60) - hctx->tx_rto = 60 * HZ; + hc->tx_rto = 60 * HZ; ccid2_start_rto_timer(sk); /* adjust pipe, cwnd etc */ - hctx->tx_ssthresh = hctx->tx_cwnd / 2; - if (hctx->tx_ssthresh < 2) - hctx->tx_ssthresh = 2; - hctx->tx_cwnd = 1; - hctx->tx_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->tx_seqt = hctx->tx_seqh; - hctx->tx_packets_acked = 0; + hc->tx_seqt = hc->tx_seqh; + hc->tx_packets_acked = 0; /* clear ack ratio state. */ - hctx->tx_rpseq = 0; - hctx->tx_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); @@ -211,40 +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->tx_rto); + ccid2_pr_debug("setting RTO timeout=%ld\n", hc->tx_rto); - BUG_ON(timer_pending(&hctx->tx_rtotimer)); - sk_reset_timer(sk, &hctx->tx_rtotimer, jiffies + hctx->tx_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->tx_pipe++; + hc->tx_pipe++; - hctx->tx_seqh->ccid2s_seq = dp->dccps_gss; - hctx->tx_seqh->ccid2s_acked = 0; - hctx->tx_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->tx_seqh->ccid2s_next; + next = hc->tx_seqh->ccid2s_next; /* check if we need to alloc more space */ - if (next == hctx->tx_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->tx_seqh->ccid2s_next; - BUG_ON(next == hctx->tx_seqt); + next = hc->tx_seqh->ccid2s_next; + BUG_ON(next == hc->tx_seqt); } - hctx->tx_seqh = next; + hc->tx_seqh = next; - ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->tx_cwnd, hctx->tx_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 @@ -267,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->tx_arsent++; + hc->tx_arsent++; /* We had an ack loss in this window... */ - if (hctx->tx_ackloss) { - if (hctx->tx_arsent >= hctx->tx_cwnd) { - hctx->tx_arsent = 0; - hctx->tx_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... */ @@ -282,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->tx_cwnd * hctx->tx_cwnd / denom; + denom = hc->tx_cwnd * hc->tx_cwnd / denom; - if (hctx->tx_arsent >= denom) { + if (hc->tx_arsent >= denom) { ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1); - hctx->tx_arsent = 0; + hc->tx_arsent = 0; } } else { /* we can't increase ack ratio further [1] */ - hctx->tx_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->tx_rtotimer)) + if (!timer_pending(&hc->tx_rtotimer)) ccid2_start_rto_timer(sk); #ifdef CONFIG_IP_DCCP_CCID2_DEBUG do { - struct ccid2_seq *seqp = hctx->tx_seqt; + struct ccid2_seq *seqp = hc->tx_seqt; - while (seqp != hctx->tx_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); @@ -311,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 } @@ -379,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->tx_rtotimer); + sk_stop_timer(sk, &hc->tx_rtotimer); ccid2_pr_debug("deleted RTO timer\n"); } @@ -389,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->tx_cwnd < hctx->tx_ssthresh) { - if (*maxincr > 0 && ++hctx->tx_packets_acked == 2) { - hctx->tx_cwnd += 1; - *maxincr -= 1; - hctx->tx_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->tx_packets_acked >= hctx->tx_cwnd) { - hctx->tx_cwnd += 1; - hctx->tx_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->tx_srtt == -1 || - time_after(jiffies, hctx->tx_lastrtt + hctx->tx_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->tx_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->tx_rttvar = r >> 1; + ccid2_change_srtt(hc, r); + hc->tx_rttvar = r >> 1; } else { /* RTTVAR */ - long tmp = hctx->tx_srtt - r; + long tmp = hc->tx_srtt - r; long srtt; if (tmp < 0) tmp *= -1; tmp >>= 2; - hctx->tx_rttvar *= 3; - hctx->tx_rttvar >>= 2; - hctx->tx_rttvar += tmp; + hc->tx_rttvar *= 3; + hc->tx_rttvar >>= 2; + hc->tx_rttvar += tmp; /* SRTT */ - srtt = hctx->tx_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->tx_rttvar << 2; + s = hc->tx_rttvar << 2; /* clock granularity is 1 when based on jiffies */ if (!s) s = 1; - hctx->tx_rto = hctx->tx_srtt + s; + hc->tx_rto = hc->tx_srtt + s; /* must be at least a second */ - s = hctx->tx_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->tx_rto = HZ; + hc->tx_rto = HZ; #endif /* max 60 seconds */ if (s > 60) - hctx->tx_rto = HZ * 60; + hc->tx_rto = HZ * 60; - hctx->tx_lastrtt = jiffies; + hc->tx_lastrtt = jiffies; ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n", - hctx->tx_srtt, hctx->tx_rttvar, - hctx->tx_rto, HZ, r); + hc->tx_srtt, hc->tx_rttvar, + hc->tx_rto, HZ, r); } /* we got a new ack, so re-start RTO timer */ @@ -467,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->tx_pipe == 0) + if (hc->tx_pipe == 0) DCCP_BUG("pipe == 0"); else - hctx->tx_pipe--; + hc->tx_pipe--; - if (hctx->tx_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->tx_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->tx_last_cong = jiffies; + hc->tx_last_cong = jiffies; - hctx->tx_cwnd = hctx->tx_cwnd / 2 ? : 1U; - hctx->tx_ssthresh = max(hctx->tx_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->tx_cwnd) - ccid2_change_l_ack_ratio(sk, hctx->tx_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; @@ -509,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; @@ -518,21 +518,21 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) * -sorbo. */ /* need to bootstrap */ - if (hctx->tx_rpdupack == -1) { - hctx->tx_rpdupack = 0; - hctx->tx_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->tx_rpseq, seqno) == 1) - hctx->tx_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->tx_rpseq)) { - hctx->tx_rpdupack++; + else if (after48(seqno, hc->tx_rpseq)) { + hc->tx_rpdupack++; /* check if we got enough dupacks */ - if (hctx->tx_rpdupack >= NUMDUPACK) { - hctx->tx_rpdupack = -1; /* XXX lame */ - hctx->tx_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); } @@ -541,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->tx_seqh == hctx->tx_seqt) + if (hc->tx_seqh == hc->tx_seqt) return; switch (DCCP_SKB_CB(skb)->dccpd_type) { @@ -553,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->tx_high_ack)) - hctx->tx_high_ack = ackno; + if (after48(ackno, hc->tx_high_ack)) + hc->tx_high_ack = ackno; - seqp = hctx->tx_seqt; + seqp = hc->tx_seqt; while (before48(seqp->ccid2s_seq, ackno)) { seqp = seqp->ccid2s_next; - if (seqp == hctx->tx_seqh) { - seqp = hctx->tx_seqh->ccid2s_prev; + if (seqp == hc->tx_seqh) { + seqp = hc->tx_seqh->ccid2s_prev; break; } } @@ -570,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->tx_cwnd < hctx->tx_ssthresh) + if (hc->tx_cwnd < hc->tx_ssthresh) maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); /* go through all ack vectors */ @@ -589,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->tx_seqt) { + if (seqp == hc->tx_seqt) { done = 1; break; } @@ -621,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->tx_seqt) { + if (seqp == hc->tx_seqt) { done = 1; break; } @@ -640,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->tx_seqt; - while (before48(seqp->ccid2s_seq, hctx->tx_high_ack)) { + seqp = hc->tx_seqt; + while (before48(seqp->ccid2s_seq, hc->tx_high_ack)) { seqp = seqp->ccid2s_next; - if (seqp == hctx->tx_seqh) { - seqp = hctx->tx_seqh->ccid2s_prev; + if (seqp == hc->tx_seqh) { + seqp = hc->tx_seqh->ccid2s_prev; break; } } @@ -655,7 +655,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) if (done == NUMDUPACK) break; } - if (seqp == hctx->tx_seqt) + if (seqp == hc->tx_seqt) break; seqp = seqp->ccid2s_prev; } @@ -678,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->tx_seqt) + if (seqp == hc->tx_seqt) break; seqp = seqp->ccid2s_prev; } - hctx->tx_seqt = last_acked; + hc->tx_seqt = last_acked; } /* trim acked packets in tail */ - while (hctx->tx_seqt != hctx->tx_seqh) { - if (!hctx->tx_seqt->ccid2s_acked) + while (hc->tx_seqt != hc->tx_seqh) { + if (!hc->tx_seqt->ccid2s_acked) break; - hctx->tx_seqt = hctx->tx_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->tx_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->tx_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->tx_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->tx_rto = 3 * HZ; - ccid2_change_srtt(hctx, -1); - hctx->tx_rttvar = -1; - hctx->tx_rpdupack = -1; - hctx->tx_last_cong = jiffies; - setup_timer(&hctx->tx_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->tx_seqbufc; i++) - kfree(hctx->tx_seqbuf[i]); - hctx->tx_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->rx_data++; - if (hcrx->rx_data >= dp->dccps_r_ack_ratio) { + hc->rx_data++; + if (hc->rx_data >= dp->dccps_r_ack_ratio) { dccp_send_ack(sk); - hcrx->rx_data = 0; + hc->rx_data = 0; } break; } -- cgit v1.2.3 From 996ccf49005662ee7fee38a45be5cb27bf370b1d Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 5 Oct 2009 00:53:13 +0000 Subject: dccp ccid-3: Remove CCID naming redundancy 2/2 This continues the previous patch, by applying the same change to CCID-3. Signed-off-by: Gerrit Renker Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ccids/ccid3.c | 371 ++++++++++++++++++++++++------------------------- net/dccp/probe.c | 12 +- 2 files changed, 191 insertions(+), 192 deletions(-) (limited to 'net') diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 6b8d67ba7fe..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->tx_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->tx_state = state; + hc->tx_state = state; } /* @@ -85,32 +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->tx_s, 4 * hctx->tx_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->tx_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->tx_t_ipi = scaled_div32(((u64)hctx->tx_s) << 6, hctx->tx_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->tx_delta = min_t(u32, hctx->tx_t_ipi / 2, TFRC_OPSYS_HALF_TIME_GRAN); + 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", hctx->tx_t_ipi, - hctx->tx_delta, hctx->tx_s, (unsigned)(hctx->tx_x >> 6)); + 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->tx_t_last_win_count); + u32 delta = ktime_us_delta(now, hc->tx_t_last_win_count); - return delta / hctx->tx_rtt; + return delta / hc->tx_rtt; } /** @@ -125,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->tx_x_recv; - const __u64 old_x = hctx->tx_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(); /* @@ -136,31 +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->tx_x_recv); + min_rate = max(min_rate, 2 * hc->tx_x_recv); } - if (hctx->tx_p > 0) { + if (hc->tx_p > 0) { - hctx->tx_x = min(((__u64)hctx->tx_x_calc) << 6, min_rate); - hctx->tx_x = max(hctx->tx_x, (((__u64)hctx->tx_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->tx_t_ld) - (s64)hctx->tx_rtt >= 0) { + } else if (ktime_us_delta(now, hc->tx_t_ld) - (s64)hc->tx_rtt >= 0) { - hctx->tx_x = min(2 * hctx->tx_x, min_rate); - hctx->tx_x = max(hctx->tx_x, scaled_div(((__u64)hctx->tx_s) << 6, - hctx->tx_rtt)); - hctx->tx_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->tx_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->tx_x >> 6), hctx->tx_x_calc, - (unsigned)(hctx->tx_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); } } @@ -168,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->tx_s; + const u16 old_s = hc->tx_s; - hctx->tx_s = tfrc_ewma(hctx->tx_s, len, 9); + hc->tx_s = tfrc_ewma(hc->tx_s, len, 9); - if (hctx->tx_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->tx_t_last_win_count), - quarter_rtts = (4 * delta) / hctx->tx_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->tx_t_last_win_count = now; - hctx->tx_last_win_count += min(quarter_rtts, 5U); - hctx->tx_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); @@ -209,23 +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->tx_state)); + ccid3_tx_state_name(hc->tx_state)); - if (hctx->tx_state == TFRC_SSTATE_FBACK) + if (hc->tx_state == TFRC_SSTATE_FBACK) ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK); - else if (hctx->tx_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->tx_t_rto == 0 || /* no feedback received yet */ - hctx->tx_p == 0) { + if (hc->tx_t_rto == 0 || /* no feedback received yet */ + hc->tx_p == 0) { /* halve send rate directly */ - hctx->tx_x = max(hctx->tx_x / 2, - (((__u64)hctx->tx_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 @@ -237,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->tx_p && !hctx->tx_x_calc); + BUG_ON(hc->tx_p && !hc->tx_x_calc); - if (hctx->tx_x_calc > (hctx->tx_x_recv >> 5)) - hctx->tx_x_recv = - max(hctx->tx_x_recv / 2, - (((__u64)hctx->tx_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->tx_x_recv = hctx->tx_x_calc; - hctx->tx_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->tx_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->tx_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->tx_t_rto, 2 * hctx->tx_t_ipi); + t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi); restart_timer: - sk_reset_timer(sk, &hctx->tx_no_feedback_timer, + sk_reset_timer(sk, &hc->tx_no_feedback_timer, jiffies + usecs_to_jiffies(t_nfb)); out: bh_unlock_sock(sk); @@ -279,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; @@ -291,17 +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->tx_state) { + switch (hc->tx_state) { case TFRC_SSTATE_NO_SENT: - sk_reset_timer(sk, &hctx->tx_no_feedback_timer, (jiffies + - usecs_to_jiffies(TFRC_INITIAL_TIMEOUT))); - hctx->tx_last_win_count = 0; - hctx->tx_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->tx_t_nom = now; + hc->tx_t_nom = now; - hctx->tx_s = skb->len; + hc->tx_s = skb->len; /* * Use initial RTT sample when available: recommended by erratum @@ -310,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->tx_rtt = dp->dccps_syn_rtt; - hctx->tx_x = rfc3390_initial_rate(sk); - hctx->tx_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: @@ -320,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->tx_rtt = DCCP_FALLBACK_RTT; - hctx->tx_x = hctx->tx_s; - hctx->tx_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->tx_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] @@ -340,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->tx_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); @@ -352,27 +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->tx_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->tx_t_nom = ktime_add_us(hctx->tx_t_nom, hctx->tx_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->tx_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; @@ -383,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->tx_state != TFRC_SSTATE_FBACK && - hctx->tx_state != TFRC_SSTATE_NO_FBACK) + if (hc->tx_state != TFRC_SSTATE_FBACK && + hc->tx_state != TFRC_SSTATE_NO_FBACK) return; - opt_recv = &hctx->tx_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->tx_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, @@ -401,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->tx_x_recv = opt_recv->ccid3or_receive_rate; - hctx->tx_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->tx_p = 0; + hc->tx_p = 0; else /* can not exceed 100% */ - hctx->tx_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->tx_rtt = tfrc_ewma(hctx->tx_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->tx_state == TFRC_SSTATE_NO_FBACK) { + if (hc->tx_state == TFRC_SSTATE_NO_FBACK) { ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); - if (hctx->tx_t_rto == 0) { + if (hc->tx_t_rto == 0) { /* * Initial feedback packet: Larger Initial Windows (4.2) */ - hctx->tx_x = rfc3390_initial_rate(sk); - hctx->tx_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->tx_p == 0) { + } else if (hc->tx_p == 0) { /* * First feedback after nofeedback timer expiry (4.3) */ @@ -440,20 +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->tx_p > 0) - hctx->tx_x_calc = tfrc_calc_x(hctx->tx_s, hctx->tx_rtt, hctx->tx_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->tx_rtt, r_sample, - hctx->tx_s, hctx->tx_p, hctx->tx_x_calc, - (unsigned)(hctx->tx_x_recv >> 6), - (unsigned)(hctx->tx_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->tx_no_feedback_timer); + sk_stop_timer(sk, &hc->tx_no_feedback_timer); /* * As we have calculated new ipi, delta, t_nom it is possible @@ -467,19 +466,19 @@ done_computing_x: * This can help avoid triggering the nofeedback timer too * often ('spinning') on LANs with small RTTs. */ - hctx->tx_t_rto = max_t(u32, 4 * hctx->tx_rtt, (CONFIG_IP_DCCP_CCID3_RTO * + 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->tx_t_rto, 2 * hctx->tx_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); - sk_reset_timer(sk, &hctx->tx_no_feedback_timer, + sk_reset_timer(sk, &hc->tx_no_feedback_timer, jiffies + usecs_to_jiffies(t_nfb)); } @@ -489,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->tx_options_received; + opt_recv = &hc->tx_options_received; if (opt_recv->ccid3or_seqno != dp->dccps_gsr) { opt_recv->ccid3or_seqno = dp->dccps_gsr; @@ -547,55 +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->tx_state = TFRC_SSTATE_NO_SENT; - hctx->tx_hist = NULL; - setup_timer(&hctx->tx_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->tx_no_feedback_timer); + sk_stop_timer(sk, &hc->tx_no_feedback_timer); - tfrc_tx_hist_purge(&hctx->tx_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->tx_t_rto; - info->tcpi_rtt = hctx->tx_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->tx_tfrc)) + if (len < sizeof(hc->tx_tfrc)) return -EINVAL; - len = sizeof(hctx->tx_tfrc); - val = &hctx->tx_tfrc; + len = sizeof(hc->tx_tfrc); + val = &hc->tx_tfrc; break; default: return -ENOPROTOOPT; @@ -635,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->rx_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->rx_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->rx_state == TFRC_RSTATE_TERM)) + if (unlikely(hc->rx_state == TFRC_RSTATE_TERM)) return; now = ktime_get_real(); switch (fbtype) { case CCID3_FBACK_INITIAL: - hcrx->rx_x_recv = 0; - hcrx->rx_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: /* @@ -675,26 +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->rx_x_recv > 0) + if (hc->rx_x_recv > 0) break; /* fall through */ case CCID3_FBACK_PERIODIC: - delta = ktime_us_delta(now, hcrx->rx_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->rx_x_recv = scaled_div32(hcrx->rx_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->rx_x_recv, hcrx->rx_pinv); + hc->rx_x_recv, hc->rx_pinv); - hcrx->rx_tstamp_last_feedback = now; - hcrx->rx_last_counter = dccp_hdr(skb)->dccph_ccval; - hcrx->rx_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); @@ -702,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->rx_x_recv); - pinv = htonl(hcrx->rx_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)) || @@ -737,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->rx_rtt == 0) { + if (hc->rx_rtt == 0) { DCCP_WARN("No RTT estimate available, using fallback RTT\n"); - hcrx->rx_rtt = DCCP_FALLBACK_RTT; + hc->rx_rtt = DCCP_FALLBACK_RTT; } - delta = ktime_to_us(net_timedelta(hcrx->rx_tstamp_last_feedback)); - x_recv = scaled_div32(hcrx->rx_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->rx_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->rx_s, hcrx->rx_rtt); + fval = scaled_div(hc->rx_s, hc->rx_rtt); fval = scaled_div32(fval, x_recv); p = tfrc_calc_x_reverse_lookup(fval); @@ -768,17 +767,17 @@ 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->rx_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->rx_s = payload; + hc->rx_s = payload; /* * Not necessary to update rx_bytes_recv here, * since X_recv = 0 for the first feedback packet (cf. @@ -788,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->rx_hist, skb)) + if (tfrc_rx_hist_duplicate(&hc->rx_hist, skb)) return; /* done receiving */ if (is_data_packet) { @@ -796,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->rx_s = tfrc_ewma(hcrx->rx_s, payload, 9); - hcrx->rx_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->rx_hist, &hcrx->rx_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->rx_hist)) + if (tfrc_rx_hist_loss_pending(&hc->rx_hist)) return; /* done receiving */ /* @@ -818,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->rx_li_hist)) { - const u32 sample = tfrc_rx_hist_sample_rtt(&hcrx->rx_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->rx_rtt = tfrc_ewma(hcrx->rx_rtt, sample, 9); + hc->rx_rtt = tfrc_ewma(hc->rx_rtt, sample, 9); - } else if (tfrc_lh_update_i_mean(&hcrx->rx_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. @@ -839,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->rx_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->rx_hist, skb, ndp); + tfrc_rx_hist_add_packet(&hc->rx_hist, skb, ndp); done_receiving: if (do_feedback) @@ -852,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->rx_state = TFRC_RSTATE_NO_DATA; - tfrc_lh_init(&hcrx->rx_li_hist); - return tfrc_rx_hist_alloc(&hcrx->rx_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->rx_hist); - tfrc_lh_cleanup(&hcrx->rx_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->rx_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->rx_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; @@ -894,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->rx_x_recv; - rx_info.tfrcrx_rtt = hcrx->rx_rtt; - rx_info.tfrcrx_p = hcrx->rx_pinv == 0 ? ~0U : - scaled_div(1, hcrx->rx_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/probe.c b/net/dccp/probe.c index 430d16fd6f5..5e6ec8b9b7b 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -75,20 +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) + 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->tx_s, hctx->tx_rtt, hctx->tx_p, - hctx->tx_x_calc, hctx->tx_x_recv >> 6, - hctx->tx_x >> 6, hctx->tx_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), -- cgit v1.2.3 From ffce908246c93b17304c313886d25cfa8aecd1d7 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Wed, 7 Oct 2009 13:55:57 -0700 Subject: net: Add sk_mark route lookup support for IPv4 listening sockets Add support for route lookup using sk_mark on IPv4 listening sockets. Signed-off-by: Atis Elsts Signed-off-by: David S. Miller --- net/ipv4/inet_connection_sock.c | 1 + net/ipv4/syncookies.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'net') 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/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), -- cgit v1.2.3 From 86c36ce45dc2e2f022562c6481cd778f4cc381a9 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Wed, 7 Oct 2009 13:58:01 -0700 Subject: IPv6: use ipv6_addr_copy() in ip6_route_redirect() Change ip6_route_redirect() to use ipv6_addr_copy(). Signed-off-by: Brian Haley Signed-off-by: David S. Miller --- net/ipv6/route.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') 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; -- cgit v1.2.3 From b301e82cf8104cfddbe5452ebe625bab49597c64 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Wed, 7 Oct 2009 13:58:25 -0700 Subject: IPv6: use ipv6_addr_set_v4mapped() Might as well use the ipv6_addr_set_v4mapped() inline we created last year. Signed-off-by: Brian Haley Signed-off-by: David S. Miller --- net/dccp/ipv6.c | 12 ++++-------- net/ipv6/datagram.c | 24 ++++++++++-------------- net/ipv6/tcp_ipv6.c | 12 ++++-------- net/ipv6/udp.c | 4 ++-- net/sunrpc/svcauth_unix.c | 3 +-- 5 files changed, 21 insertions(+), 34 deletions(-) (limited to 'net') 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/ipv6/datagram.c b/net/ipv6/datagram.c index a615b4dea6c..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; } @@ -330,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); } } @@ -352,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/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 321aafd40dc..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; @@ -1293,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); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3842c557d6f..c6a303ec834 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -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); 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); -- cgit v1.2.3 From 9e8342971d44ce86d8567047f5366fc1c06a75ed Mon Sep 17 00:00:00 2001 From: Hagen Paul Pfeifer Date: Wed, 7 Oct 2009 14:43:04 -0700 Subject: econet: Fix redeclaration of symbol len Function argument len was redeclarated within the function. This patch fix the redeclaration of symbol 'len'. Signed-off-by: Hagen Paul Pfeifer Signed-off-by: David S. Miller --- net/econet/af_econet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 6529be3a18b..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) */ -- cgit v1.2.3 From 4b17d50f9e9034be3fe0414dc3492c0071dba75c Mon Sep 17 00:00:00 2001 From: Hagen Paul Pfeifer Date: Wed, 7 Oct 2009 14:45:58 -0700 Subject: ipv4: Define cipso_v4_delopt static There is no reason that cipso_v4_delopt() is not defined as a static function. Signed-off-by: Hagen Paul Pfeifer Signed-off-by: David S. Miller --- net/ipv4/cipso_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') 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; -- cgit v1.2.3 From 8a6dfd43d1891882f8ca05d73aa7735fb0edae3b Mon Sep 17 00:00:00 2001 From: Alexandre Cassen Date: Wed, 7 Oct 2009 14:50:30 -0700 Subject: IPv6: Fix 6RD typo Following fix a small typo. Signed-off-by: Alexandre Cassen Signed-off-by: David S. Miller --- net/ipv6/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index f5619982745..a578096152a 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -171,7 +171,7 @@ config IPV6_SIT Saying M here will produce a module called sit. If unsure, say Y. config IPV6_SIT_6RD - bool "IPv6: IPv6 Rapid Development (6RD) (EXPERIMENTAL)" + bool "IPv6: IPv6 Rapid Deployment (6RD) (EXPERIMENTAL)" depends on IPV6_SIT && EXPERIMENTAL default n ---help--- -- cgit v1.2.3 From f86dcc5aa8c7908f2c287e7a211228df599e3e71 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Oct 2009 00:37:59 +0000 Subject: udp: dynamically size hash tables at boot time UDP_HTABLE_SIZE was initialy defined to 128, which is a bit small for several setups. 4000 active UDP sockets -> 32 sockets per chain in average. An incoming frame has to lookup all sockets to find best match, so long chains hurt latency. Instead of a fixed size hash table that cant be perfect for every needs, let UDP stack choose its table size at boot time like tcp/ip route, using alloc_large_system_hash() helper Add an optional boot parameter, uhash_entries=x so that an admin can force a size between 256 and 65536 if needed, like thash_entries and rhash_entries. dmesg logs two new lines : [ 0.647039] UDP hash table entries: 512 (order: 0, 4096 bytes) [ 0.647099] UDP Lite hash table entries: 512 (order: 0, 4096 bytes) Maximal size on 64bit arches would be 65536 slots, ie 1 MBytes for non debugging spinlocks. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/kernel-parameters.txt | 3 ++ include/linux/udp.h | 6 +-- include/net/udp.h | 13 ++++-- net/ipv4/udp.c | 91 +++++++++++++++++++++++++++---------- net/ipv4/udplite.c | 4 +- net/ipv6/udp.c | 6 +-- 6 files changed, 87 insertions(+), 36 deletions(-) (limited to 'net') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6fa7292947e..02df20be776 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2589,6 +2589,9 @@ and is between 256 and 4096 characters. It is defined in the file uart6850= [HW,OSS] Format: , + uhash_entries= [KNL,NET] + Set number of hash buckets for UDP/UDP-Lite connections + uhci-hcd.ignore_oc= [USB] Ignore overcurrent events (default N). Some badly-designed motherboards generate lots of diff --git a/include/linux/udp.h b/include/linux/udp.h index 0cf5c4c0ec8..832361e3e59 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -45,11 +45,11 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb) return (struct udphdr *)skb_transport_header(skb); } -#define UDP_HTABLE_SIZE 128 +#define UDP_HTABLE_SIZE_MIN (CONFIG_BASE_SMALL ? 128 : 256) -static inline int udp_hashfn(struct net *net, const unsigned num) +static inline int udp_hashfn(struct net *net, unsigned num, unsigned mask) { - return (num + net_hash_mix(net)) & (UDP_HTABLE_SIZE - 1); + return (num + net_hash_mix(net)) & mask; } struct udp_sock { diff --git a/include/net/udp.h b/include/net/udp.h index f98abd2ce70..22aa2e7eb1d 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -54,12 +54,19 @@ struct udp_hslot { struct hlist_nulls_head head; spinlock_t lock; } __attribute__((aligned(2 * sizeof(long)))); + struct udp_table { - struct udp_hslot hash[UDP_HTABLE_SIZE]; + struct udp_hslot *hash; + unsigned int mask; + unsigned int log; }; extern struct udp_table udp_table; -extern void udp_table_init(struct udp_table *); - +extern void udp_table_init(struct udp_table *, const char *); +static inline struct udp_hslot *udp_hashslot(struct udp_table *table, + struct net *net, unsigned num) +{ + return &table->hash[udp_hashfn(net, num, table->mask)]; +} /* Note: this must match 'valbool' in sock_setsockopt */ #define UDP_CSUM_NOXMIT 1 diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6ec6a8a4a22..194bcdc6d9f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -106,7 +106,7 @@ #include #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; @@ -1013,8 +1017,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)) { @@ -1169,7 +1173,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); @@ -1609,9 +1613,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)) @@ -1636,7 +1645,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); } @@ -1656,7 +1665,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; } @@ -1678,7 +1687,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); } @@ -1738,7 +1747,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), @@ -1804,11 +1813,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); } @@ -1818,7 +1859,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/udp.c b/net/ipv6/udp.c index c6a303ec834..ff778c172ef 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; @@ -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); @@ -1197,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], -- cgit v1.2.3 From d9f5950f90292f7cc42834338dfd5f44dc4cc4ca Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Wed, 7 Oct 2009 12:24:25 +0000 Subject: net: Make UFO on master device independent of attached devices Now that software UFO is supported, UFO can be enabled on master devices like bridge, bond even though the attached device doesn't support this feature in hardware. This allows UFO to be used between KVM host and guest even when a physical interface attached to the bridge doesn't support UFO. Signed-off-by: Sridhar Samudrala Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index a74c8fd6955..510ff205d5d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5489,7 +5489,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; -- cgit v1.2.3 From 72dad218f872dbd53f5dc5df9df45709e4b77870 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Wed, 7 Oct 2009 12:41:17 +0000 Subject: bridge: Allow enable/disable UFO on bridge device via ethtool Allow enable/disable UFO on bridge device via ethtool Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/bridge/br_device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') 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, }; -- cgit v1.2.3 From e0c93948154328e13b4c0b0502d66af93f0fdfc4 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Sun, 11 Oct 2009 03:31:34 +0000 Subject: ipv6 sit: Ensure to initialize 6rd parameters. ipv6 sit: Ensure to initialize 6rd parameters. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/sit.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 6955654262a..8594451c747 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -161,9 +161,11 @@ 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 ip_tunnel *t, struct sit_net *sitn) +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; @@ -219,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; @@ -228,8 +231,6 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, dev_hold(dev); - ipip6_tunnel_clone_6rd(t, sitn); - ipip6_tunnel_link(sitn, nt); return nt; @@ -1024,7 +1025,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t->ip6rd.prefixlen = ip6rd.prefixlen; t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen; } else - ipip6_tunnel_clone_6rd(t, sitn); + ipip6_tunnel_clone_6rd(dev, sitn); err = 0; break; @@ -1148,6 +1149,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; -- cgit v1.2.3 From e7db38c38fe8df1d890ae772737e27308bdc5956 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Sun, 11 Oct 2009 03:44:45 +0000 Subject: ipv6 sit: Fix 6rd relay address. ipv6 sit: Fix 6rd relay address. Relay's address should be extracted from real IPv6 address instead of configured prefix. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/sit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 8594451c747..193d0c6c5ce 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -569,12 +569,12 @@ __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel) pbw0 = tunnel->ip6rd.prefixlen >> 5; pbi0 = tunnel->ip6rd.prefixlen & 0x1f; - d = (ntohl(tunnel->ip6rd.prefix.s6_addr32[pbw0]) << pbi0) >> + d = (ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >> tunnel->ip6rd.relay_prefixlen; pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen; if (pbi1 > 0) - d |= ntohl(tunnel->ip6rd.prefix.s6_addr32[pbw0 + 1]) >> + d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> (32 - pbi1); dst = tunnel->ip6rd.relay_prefix | htonl(d); -- cgit v1.2.3 From 91b2a3f9bb0fa8d64b365a10b0624b0341e1a338 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Sun, 11 Oct 2009 03:45:13 +0000 Subject: ipv6 sit: Set relay to 0.0.0.0 directly if relay_prefixlen == 0. ipv6 sit: Set relay to 0.0.0.0 directly if relay_prefixlen == 0. Do not use bit-shift if relay_prefixlen == 0; relay_prefix << 32 does not result in 0. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/sit.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 193d0c6c5ce..510d31f3cb9 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1014,9 +1014,12 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ip6rd.prefixlen); if (!ipv6_addr_equal(&prefix, &ip6rd.prefix)) goto done; - relay_prefix = ip6rd.relay_prefix & - htonl(0xffffffffUL << - (32 - ip6rd.relay_prefixlen)); + 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; -- cgit v1.2.3 From d5e63bded6e819ca77ee1a1d97c783a31f6caf30 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 12 Oct 2009 03:00:31 -0700 Subject: Revert "af_packet: add interframe drop cmsg (v6)" This reverts commit 977750076d98c7ff6cbda51858bb5a5894a9d9ab. Neil is reimplementing this generically, outside of AF_PACKET. Signed-off-by: David S. Miller --- include/linux/if_packet.h | 2 -- net/packet/af_packet.c | 33 --------------------------------- 2 files changed, 35 deletions(-) (limited to 'net') diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index e5d200f53fc..dea7d6b7cf9 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -48,13 +48,11 @@ struct sockaddr_ll #define PACKET_RESERVE 12 #define PACKET_TX_RING 13 #define PACKET_LOSS 14 -#define PACKET_GAPDATA 15 struct tpacket_stats { unsigned int tp_packets; unsigned int tp_drops; - unsigned int tp_gap; }; struct tpacket_auxdata diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 70073a0dea5..f87ed4803c1 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -524,31 +524,6 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk, return res; } -/* - * If we've lost frames since the last time we queued one to the - * sk_receive_queue, we need to record it here. - * This must be called under the protection of the socket lock - * to prevent racing with other softirqs and user space - */ -static inline void record_packet_gap(struct sk_buff *skb, - struct packet_sock *po) -{ - /* - * We overload the mark field here, since we're about - * to enqueue to a receive queue and no body else will - * use this field at this point - */ - skb->mark = po->stats.tp_gap; - po->stats.tp_gap = 0; - return; - -} - -static inline __u32 check_packet_gap(struct sk_buff *skb) -{ - return skb->mark; -} - /* This function makes lazy skb cloning in hope that most of packets are discarded by BPF. @@ -652,7 +627,6 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, spin_lock(&sk->sk_receive_queue.lock); po->stats.tp_packets++; - record_packet_gap(skb, po); __skb_queue_tail(&sk->sk_receive_queue, skb); spin_unlock(&sk->sk_receive_queue.lock); sk->sk_data_ready(sk, skb->len); @@ -661,7 +635,6 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, drop_n_acct: spin_lock(&sk->sk_receive_queue.lock); po->stats.tp_drops++; - po->stats.tp_gap++; spin_unlock(&sk->sk_receive_queue.lock); drop_n_restore: @@ -839,7 +812,6 @@ drop: ring_is_full: po->stats.tp_drops++; - po->stats.tp_gap++; spin_unlock(&sk->sk_receive_queue.lock); sk->sk_data_ready(sk, 0); @@ -1449,7 +1421,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; int copied, err; struct sockaddr_ll *sll; - __u32 gap; err = -EINVAL; if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) @@ -1528,10 +1499,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); } - gap = check_packet_gap(skb); - if (gap) - put_cmsg(msg, SOL_PACKET, PACKET_GAPDATA, sizeof(__u32), &gap); - /* * Free or return the buffer as appropriate. Again this * hides all the races and re-entrancy issues from us. -- cgit v1.2.3 From 3b885787ea4112eaa80945999ea0901bf742707f Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 12 Oct 2009 13:26:31 -0700 Subject: net: Generalize socket rx gap / receive queue overflow cmsg Create a new socket level option to report number of queue overflows Recently I augmented the AF_PACKET protocol to report the number of frames lost on the socket receive queue between any two enqueued frames. This value was exported via a SOL_PACKET level cmsg. AFter I completed that work it was requested that this feature be generalized so that any datagram oriented socket could make use of this option. As such I've created this patch, It creates a new SOL_SOCKET level option called SO_RXQ_OVFL, which when enabled exports a SOL_SOCKET level cmsg that reports the nubmer of times the sk_receive_queue overflowed between any two given frames. It also augments the AF_PACKET protocol to take advantage of this new feature (as it previously did not touch sk->sk_drops, which this patch uses to record the overflow count). Tested successfully by me. Notes: 1) Unlike my previous patch, this patch simply records the sk_drops value, which is not a number of drops between packets, but rather a total number of drops. Deltas must be computed in user space. 2) While this patch currently works with datagram oriented protocols, it will also be accepted by non-datagram oriented protocols. I'm not sure if thats agreeable to everyone, but my argument in favor of doing so is that, for those protocols which aren't applicable to this option, sk_drops will always be zero, and reporting no drops on a receive queue that isn't used for those non-participating protocols seems reasonable to me. This also saves us having to code in a per-protocol opt in mechanism. 3) This applies cleanly to net-next assuming that commit 977750076d98c7ff6cbda51858bb5a5894a9d9ab (my af packet cmsg patch) is reverted Signed-off-by: Neil Horman Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- arch/alpha/include/asm/socket.h | 2 ++ arch/arm/include/asm/socket.h | 2 ++ arch/avr32/include/asm/socket.h | 2 ++ arch/cris/include/asm/socket.h | 2 ++ arch/frv/include/asm/socket.h | 2 ++ arch/h8300/include/asm/socket.h | 2 ++ arch/ia64/include/asm/socket.h | 2 ++ arch/m32r/include/asm/socket.h | 2 ++ arch/m68k/include/asm/socket.h | 2 ++ arch/mips/include/asm/socket.h | 2 ++ arch/mn10300/include/asm/socket.h | 2 ++ arch/parisc/include/asm/socket.h | 2 ++ arch/powerpc/include/asm/socket.h | 2 ++ arch/s390/include/asm/socket.h | 2 ++ arch/sparc/include/asm/socket.h | 2 ++ arch/xtensa/include/asm/socket.h | 2 ++ include/asm-generic/socket.h | 1 + include/linux/skbuff.h | 6 ++++-- include/net/sock.h | 3 +++ net/atm/common.c | 2 +- net/bluetooth/af_bluetooth.c | 2 +- net/bluetooth/rfcomm/sock.c | 2 +- net/can/bcm.c | 2 +- net/can/raw.c | 2 +- net/core/sock.c | 17 ++++++++++++++++- net/ieee802154/dgram.c | 2 +- net/ieee802154/raw.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/raw.c | 2 +- net/ipv6/udp.c | 2 +- net/key/af_key.c | 2 +- net/packet/af_packet.c | 7 +++---- net/rxrpc/ar-recvmsg.c | 2 +- net/sctp/socket.c | 2 +- net/socket.c | 15 +++++++++++++++ 36 files changed, 88 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 26773e3246e..06edfefc337 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -67,6 +67,8 @@ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 40 + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index 92ac61d294f..90ffd04b8e7 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -60,4 +60,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index fe863f9794d..c8d1fae4947 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -60,4 +60,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index 45ec49bdb7b..1a4a61909ca 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -62,6 +62,8 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index 2dea726095c..a6b26880c1e 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -60,5 +60,7 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index 1547f01c8e2..04c0f4596eb 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -60,4 +60,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 0b0d5ff062e..51427eaa51b 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -69,4 +69,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index 3390a864f22..469787c3009 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -60,4 +60,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index eee01cce921..9bf49c87d95 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -60,4 +60,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index ae05accd9fe..9de5190f248 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -80,6 +80,8 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_TIMESTAMPING 37 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 40 + #ifdef __KERNEL__ /** sock_type - Socket types diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 4df75af29d7..4e60c428128 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -60,4 +60,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index 960b1e5d8e1..225b7d6a1a0 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -59,6 +59,8 @@ #define SO_TIMESTAMPING 0x4020 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 0x4021 + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 3ab8b3e6feb..866f7606da6 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -67,4 +67,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index e42df89a0b8..fdff1e995c7 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -68,4 +68,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 3a5ae3d1208..9d3fefcff2f 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -56,6 +56,8 @@ #define SO_TIMESTAMPING 0x0023 #define SCM_TIMESTAMPING SO_TIMESTAMPING +#define SO_RXQ_OVFL 0x0024 + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index beb3a6bdb61..cbdf2ffaacf 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -71,4 +71,6 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 + #endif /* _XTENSA_SOCKET_H */ diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h index 538991cef6f..9a6115e7cf6 100644 --- a/include/asm-generic/socket.h +++ b/include/asm-generic/socket.h @@ -63,4 +63,5 @@ #define SO_PROTOCOL 38 #define SO_DOMAIN 39 +#define SO_RXQ_OVFL 40 #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index df7b23ac66e..8c866b5cb97 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -389,8 +389,10 @@ struct sk_buff { #ifdef CONFIG_NETWORK_SECMARK __u32 secmark; #endif - - __u32 mark; + union { + __u32 mark; + __u32 dropcount; + }; __u16 vlan_tci; diff --git a/include/net/sock.h b/include/net/sock.h index 98398bdec57..10669b01eea 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -505,6 +505,7 @@ enum sock_flags { SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SOF_TIMESTAMPING_RAW_HARDWARE */ SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SOF_TIMESTAMPING_SYS_HARDWARE */ SOCK_FASYNC, /* fasync() active */ + SOCK_RXQ_OVFL, }; static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) @@ -1493,6 +1494,8 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) sk->sk_stamp = kt; } +extern void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb); + /** * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped * @msg: outgoing packet 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/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 1f6e49c1cde..399e59c9c6c 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -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/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index c7078650385..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); 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/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/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/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/udp.c b/net/ipv4/udp.c index 194bcdc6d9f..71e5353b30c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -955,7 +955,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) { 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/udp.c b/net/ipv6/udp.c index ff778c172ef..1f8e2afa449 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -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) { diff --git a/net/key/af_key.c b/net/key/af_key.c index c078ae6e975..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; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f87ed4803c1..bf3a2954cd4 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -627,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)) { @@ -1478,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, 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/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 954f3381cc8..80793569384 100644 --- a/net/socket.c +++ b/net/socket.c @@ -668,6 +668,21 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, EXPORT_SYMBOL_GPL(__sock_recv_timestamp); +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(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) { -- cgit v1.2.3 From a2e2725541fad72416326798c2d7fa4dafb7d337 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 12 Oct 2009 23:40:10 -0700 Subject: net: Introduce recvmmsg socket syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meaning receive multiple messages, reducing the number of syscalls and net stack entry/exit operations. Next patches will introduce mechanisms where protocols that want to optimize this operation will provide an unlocked_recvmsg operation. This takes into account comments made by: . Paul Moore: sock_recvmsg is called only for the first datagram, sock_recvmsg_nosec is used for the rest. . Caitlin Bestler: recvmmsg now has a struct timespec timeout, that works in the same fashion as the ppoll one. If the underlying protocol returns a datagram with MSG_OOB set, this will make recvmmsg return right away with as many datagrams (+ the OOB one) it has received so far. . Rémi Denis-Courmont & Steven Whitehouse: If we receive N < vlen datagrams and then recvmsg returns an error, recvmmsg will return the successfully received datagrams, store the error and return it in the next call. This paves the way for a subsequent optimization, sk_prot->unlocked_recvmsg, where we will be able to acquire the lock only at batch start and end, not at every underlying recvmsg call. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- arch/alpha/kernel/systbls.S | 1 + arch/arm/kernel/calls.S | 1 + arch/avr32/kernel/syscall_table.S | 1 + arch/blackfin/mach-common/entry.S | 1 + arch/ia64/kernel/entry.S | 1 + arch/microblaze/kernel/syscall_table.S | 1 + arch/mips/kernel/scall32-o32.S | 1 + arch/mips/kernel/scall64-64.S | 1 + arch/mips/kernel/scall64-n32.S | 1 + arch/mips/kernel/scall64-o32.S | 1 + arch/sh/kernel/syscalls_64.S | 1 + arch/sparc/kernel/systbls_32.S | 2 +- arch/sparc/kernel/systbls_64.S | 4 +- arch/x86/ia32/ia32entry.S | 1 + arch/x86/include/asm/unistd_32.h | 3 +- arch/x86/include/asm/unistd_64.h | 2 + arch/x86/kernel/syscall_table_32.S | 1 + arch/xtensa/include/asm/unistd.h | 4 +- include/linux/net.h | 1 + include/linux/socket.h | 10 ++ include/linux/syscalls.h | 4 + include/net/compat.h | 8 ++ kernel/sys_ni.c | 2 + net/compat.c | 33 ++++- net/socket.c | 225 +++++++++++++++++++++++++++------ 25 files changed, 261 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index 95c9aef1c10..cda6b8b3d57 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -497,6 +497,7 @@ sys_call_table: .quad sys_signalfd .quad sys_ni_syscall .quad sys_eventfd + .quad sys_recvmmsg .size sys_call_table, . - sys_call_table .type sys_call_table, @object diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index fafce1b5c69..f58c1156e77 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -374,6 +374,7 @@ CALL(sys_pwritev) CALL(sys_rt_tgsigqueueinfo) CALL(sys_perf_event_open) +/* 365 */ CALL(sys_recvmmsg) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S index 7ee0057613b..e76bad16b0f 100644 --- a/arch/avr32/kernel/syscall_table.S +++ b/arch/avr32/kernel/syscall_table.S @@ -295,4 +295,5 @@ sys_call_table: .long sys_signalfd .long sys_ni_syscall /* 280, was sys_timerfd */ .long sys_eventfd + .long sys_recvmmsg .long sys_ni_syscall /* r8 is saturated at nr_syscalls */ diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 1e7cac23e25..48692724b74 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -1621,6 +1621,7 @@ ENTRY(_sys_call_table) .long _sys_pwritev .long _sys_rt_tgsigqueueinfo .long _sys_perf_event_open + .long _sys_recvmmsg /* 370 */ .rept NR_syscalls-(.-_sys_call_table)/4 .long _sys_ni_syscall diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index d0e7d37017b..d75b872ca4d 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1806,6 +1806,7 @@ sys_call_table: data8 sys_preadv data8 sys_pwritev // 1320 data8 sys_rt_tgsigqueueinfo + data8 sys_recvmmsg .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */ diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index ecec1915513..c1ab1dc1089 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -371,3 +371,4 @@ ENTRY(sys_call_table) .long sys_ni_syscall .long sys_rt_tgsigqueueinfo /* 365 */ .long sys_perf_event_open + .long sys_recvmmsg diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index fd2a9bb620d..17202bbe843 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -583,6 +583,7 @@ einval: li v0, -ENOSYS sys sys_rt_tgsigqueueinfo 4 sys sys_perf_event_open 5 sys sys_accept4 4 + sys sys_recvmmsg 5 .endm /* We pre-compute the number of _instruction_ bytes needed to diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 18bf7f32c5e..a8a6c596eb0 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -420,4 +420,5 @@ sys_call_table: PTR sys_rt_tgsigqueueinfo PTR sys_perf_event_open PTR sys_accept4 + PTR sys_recvmmsg .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 6ebc0797669..5154e64f7cf 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -418,4 +418,5 @@ EXPORT(sysn32_call_table) PTR compat_sys_rt_tgsigqueueinfo /* 5295 */ PTR sys_perf_event_open PTR sys_accept4 + PTR compat_sys_recvmmsg .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 9bbf9775e0b..d0eff53d7cb 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -538,4 +538,5 @@ sys_call_table: PTR compat_sys_rt_tgsigqueueinfo PTR sys_perf_event_open PTR sys_accept4 + PTR compat_sys_recvmmsg .size sys_call_table,.-sys_call_table diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index 5bfde6c7749..07d2aaea9ae 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -391,3 +391,4 @@ sys_call_table: .long sys_pwritev .long sys_rt_tgsigqueueinfo .long sys_perf_event_open + .long sys_recvmmsg /* 365 */ diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 0f1658d3749..ceb1530f8aa 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -82,5 +82,5 @@ sys_call_table: /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv -/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open +/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 009825f6e73..f37bef747e6 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -83,7 +83,7 @@ sys_call_table32: /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv - .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open + .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg #endif /* CONFIG_COMPAT */ @@ -158,4 +158,4 @@ sys_call_table: /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv - .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open + .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 74619c4f9fd..11a6c79d5f4 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -832,4 +832,5 @@ ia32_sys_call_table: .quad compat_sys_pwritev .quad compat_sys_rt_tgsigqueueinfo /* 335 */ .quad sys_perf_event_open + .quad compat_sys_recvmmsg ia32_syscall_end: diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h index 6fb3c209a7e..3baf379fa84 100644 --- a/arch/x86/include/asm/unistd_32.h +++ b/arch/x86/include/asm/unistd_32.h @@ -342,10 +342,11 @@ #define __NR_pwritev 334 #define __NR_rt_tgsigqueueinfo 335 #define __NR_perf_event_open 336 +#define __NR_recvmmsg 337 #ifdef __KERNEL__ -#define NR_syscalls 337 +#define NR_syscalls 338 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h index 8d3ad0adbc6..4843f7ba754 100644 --- a/arch/x86/include/asm/unistd_64.h +++ b/arch/x86/include/asm/unistd_64.h @@ -661,6 +661,8 @@ __SYSCALL(__NR_pwritev, sys_pwritev) __SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo) #define __NR_perf_event_open 298 __SYSCALL(__NR_perf_event_open, sys_perf_event_open) +#define __NR_recvmmsg 299 +__SYSCALL(__NR_recvmmsg, sys_recvmmsg) #ifndef __NO_STUBS #define __ARCH_WANT_OLD_READDIR diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S index 0157cd26d7c..70c2125d55b 100644 --- a/arch/x86/kernel/syscall_table_32.S +++ b/arch/x86/kernel/syscall_table_32.S @@ -336,3 +336,4 @@ ENTRY(sys_call_table) .long sys_pwritev .long sys_rt_tgsigqueueinfo /* 335 */ .long sys_perf_event_open + .long sys_recvmmsg diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h index c092c8fbb2c..4e55dc76302 100644 --- a/arch/xtensa/include/asm/unistd.h +++ b/arch/xtensa/include/asm/unistd.h @@ -681,8 +681,10 @@ __SYSCALL(304, sys_signalfd, 3) __SYSCALL(305, sys_ni_syscall, 0) #define __NR_eventfd 306 __SYSCALL(306, sys_eventfd, 1) +#define __NR_recvmmsg 307 +__SYSCALL(307, sys_recvmmsg, 5) -#define __NR_syscall_count 307 +#define __NR_syscall_count 308 /* * sysxtensa syscall handler diff --git a/include/linux/net.h b/include/linux/net.h index 529a0931711..b42bb60fe92 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -41,6 +41,7 @@ #define SYS_SENDMSG 16 /* sys_sendmsg(2) */ #define SYS_RECVMSG 17 /* sys_recvmsg(2) */ #define SYS_ACCEPT4 18 /* sys_accept4(2) */ +#define SYS_RECVMMSG 19 /* sys_recvmmsg(2) */ typedef enum { SS_FREE = 0, /* not allocated */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 3273a0c5043..59966f12990 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -65,6 +65,12 @@ struct msghdr { unsigned msg_flags; }; +/* For recvmmsg/sendmmsg */ +struct mmsghdr { + struct msghdr msg_hdr; + unsigned msg_len; +}; + /* * POSIX 1003.1g - ancillary data object information * Ancillary data consits of a sequence of pairs of @@ -312,6 +318,10 @@ extern int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uadd extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); +struct timespec; + +extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + unsigned int flags, struct timespec *timeout); #endif #endif /* not kernel and not glibc */ #endif /* _LINUX_SOCKET_H */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index a990ace1a83..714f063a3e6 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -25,6 +25,7 @@ struct linux_dirent64; struct list_head; struct msgbuf; struct msghdr; +struct mmsghdr; struct msqid_ds; struct new_utsname; struct nfsctl_arg; @@ -677,6 +678,9 @@ asmlinkage long sys_recv(int, void __user *, size_t, unsigned); asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *); asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); +asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, + unsigned int vlen, unsigned flags, + struct timespec __user *timeout); asmlinkage long sys_socket(int, int, int); asmlinkage long sys_socketpair(int, int, int, int __user *); asmlinkage long sys_socketcall(int call, unsigned long __user *args); diff --git a/include/net/compat.h b/include/net/compat.h index 7c3002832d0..9679f05e989 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -18,6 +18,11 @@ struct compat_msghdr { compat_uint_t msg_flags; }; +struct compat_mmsghdr { + struct compat_msghdr msg_hdr; + compat_uint_t msg_len; +}; + struct compat_cmsghdr { compat_size_t cmsg_len; compat_int_t cmsg_level; @@ -35,6 +40,9 @@ extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr *, int); extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned); extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned); +extern asmlinkage long compat_sys_recvmmsg(int, struct compat_mmsghdr __user *, + unsigned, unsigned, + struct timespec __user *); extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *); extern int put_cmsg_compat(struct msghdr*, int, int, int, void *); diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index e06d0b8d195..f050ba85d42 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -48,8 +48,10 @@ cond_syscall(sys_shutdown); cond_syscall(sys_sendmsg); cond_syscall(compat_sys_sendmsg); cond_syscall(sys_recvmsg); +cond_syscall(sys_recvmmsg); cond_syscall(compat_sys_recvmsg); cond_syscall(compat_sys_recvfrom); +cond_syscall(compat_sys_recvmmsg); cond_syscall(sys_socketcall); cond_syscall(sys_futex); cond_syscall(compat_sys_futex); 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/socket.c b/net/socket.c index 80793569384..9dff31c9b79 100644 --- a/net/socket.c +++ b/net/socket.c @@ -683,10 +683,9 @@ void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, } EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops); -static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size, int flags) +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; @@ -695,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) { @@ -717,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) { @@ -1983,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; @@ -2008,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; } /* @@ -2036,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; @@ -2084,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 @@ -2118,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]; @@ -2196,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]); -- cgit v1.2.3 From c3faca053d0a9c877597935b434150b422dbc6fb Mon Sep 17 00:00:00 2001 From: Cosmin Ratiu Date: Fri, 9 Oct 2009 03:11:14 +0000 Subject: ipv6: fix devconf after adding force_tllao option Signed-off-by: Cosmin Ratiu Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index bdcee6981c6..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) -- cgit v1.2.3 From f373b53b5fe67aa4a6f28f921a529cc90f88e79b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Oct 2009 00:16:19 +0000 Subject: tcp: replace ehash_size by ehash_mask Storing the mask (size - 1) instead of the size allows fast path to be a bit faster. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 4 ++-- net/dccp/proto.c | 13 +++++++------ net/ipv4/inet_diag.c | 2 +- net/ipv4/inet_hashtables.c | 2 +- net/ipv4/inet_timewait_sock.c | 2 +- net/ipv4/tcp.c | 11 +++++------ net/ipv4/tcp_ipv4.c | 6 +++--- net/ipv6/inet6_hashtables.c | 2 +- 8 files changed, 21 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index d522dcf3031..5f11c4a0dac 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -125,7 +125,7 @@ struct inet_hashinfo { */ struct inet_ehash_bucket *ehash; spinlock_t *ehash_locks; - unsigned int ehash_size; + unsigned int ehash_mask; unsigned int ehash_locks_mask; /* Ok, let's try this, I give up, we do need a local binding @@ -158,7 +158,7 @@ static inline struct inet_ehash_bucket *inet_ehash_bucket( struct inet_hashinfo *hashinfo, unsigned int hash) { - return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)]; + return &hashinfo->ehash[hash & hashinfo->ehash_mask]; } static inline spinlock_t *inet_ehash_lockp( 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/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/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/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]; -- cgit v1.2.3 From 06a96b33aea838b61a6eeccded781a305cf85a12 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Wed, 7 Oct 2009 00:59:42 +0000 Subject: x25: bit and/or confusion in x25_ioctl()? Looking at commit ebc3f64b864f it appears that this was intended and not the original, equivalent to `if (facilities.reverse & ~0x81)'. In x25_parse_facilities() that patch changed how facilities->reverse was set. No other bits were set than 0x80 and/or 0x01. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- net/x25/af_x25.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index ebbfe6bbbff..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; -- cgit v1.2.3 From 89d71a66c40d629e3b1285def543ab1425558cd5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Oct 2009 05:34:20 +0000 Subject: net: Use netdev_alloc_skb_ip_align() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 3 +-- drivers/net/8139cp.c | 8 ++------ drivers/net/8139too.c | 3 +-- drivers/net/atl1e/atl1e_main.c | 4 +--- drivers/net/atlx/atl1.c | 11 ++--------- drivers/net/atlx/atl2.c | 3 +-- drivers/net/bcm63xx_enet.c | 5 +---- drivers/net/benet/be_main.c | 4 +--- drivers/net/cpmac.c | 6 ++---- drivers/net/dl2k.c | 18 +++++++----------- drivers/net/e100.c | 5 ++--- drivers/net/e1000/e1000_main.c | 29 +++++++---------------------- drivers/net/e1000e/netdev.c | 37 +++++++------------------------------ drivers/net/ehea/ehea_main.c | 9 +++++---- drivers/net/enic/enic_main.c | 15 +-------------- drivers/net/ethoc.c | 4 ++-- drivers/net/hamachi.c | 12 ++++++------ drivers/net/igb/igb_main.c | 8 +------- drivers/net/igbvf/netdev.c | 8 +------- drivers/net/ipg.c | 7 +------ drivers/net/ixgb/ixgb_main.c | 12 ++---------- drivers/net/ixgbe/ixgbe_main.c | 12 ++---------- drivers/net/ixp2000/ixpdev.c | 3 +-- drivers/net/korina.c | 5 +---- drivers/net/ks8842.c | 5 +---- drivers/net/lib82596.c | 11 +++++------ drivers/net/r8169.c | 3 +-- drivers/net/sc92031.c | 4 +--- drivers/net/sgiseeq.c | 7 +++---- drivers/net/sis190.c | 3 +-- drivers/net/skge.c | 7 +++---- drivers/net/sky2.c | 3 +-- drivers/net/tlan.c | 7 +++---- drivers/net/tsi108_eth.c | 10 +++------- drivers/net/via-rhine.c | 8 ++++---- drivers/net/via-velocity.c | 3 +-- drivers/net/virtio_net.c | 7 ++----- net/core/dev.c | 13 +++---------- 38 files changed, 90 insertions(+), 232 deletions(-) (limited to 'net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 975e25b19eb..32031eaf491 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2560,7 +2560,7 @@ boomerang_rx(struct net_device *dev) struct sk_buff *skb; entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { - skb = netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ); if (skb == NULL) { static unsigned long last_jif; if (time_after(jiffies, last_jif + 10 * HZ)) { @@ -2572,7 +2572,6 @@ boomerang_rx(struct net_device *dev) break; /* Bad news! */ } - skb_reserve(skb, NET_IP_ALIGN); vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); vp->rx_skbuff[entry] = skb; } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 83a1922e68e..ab451bb8995 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -549,14 +549,12 @@ rx_status_loop: pr_debug("%s: rx slot %d status 0x%x len %d\n", dev->name, rx_tail, status, len); - new_skb = netdev_alloc_skb(dev, buflen + NET_IP_ALIGN); + new_skb = netdev_alloc_skb_ip_align(dev, buflen); if (!new_skb) { dev->stats.rx_dropped++; goto rx_next; } - skb_reserve(new_skb, NET_IP_ALIGN); - dma_unmap_single(&cp->pdev->dev, mapping, buflen, PCI_DMA_FROMDEVICE); @@ -1057,12 +1055,10 @@ static int cp_refill_rx(struct cp_private *cp) struct sk_buff *skb; dma_addr_t mapping; - skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(dev, cp->rx_buf_sz); if (!skb) goto err_out; - skb_reserve(skb, NET_IP_ALIGN); - mapping = dma_map_single(&cp->pdev->dev, skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); cp->rx_skb[i] = skb; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 4a362875502..7e333f73b22 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2004,9 +2004,8 @@ no_early_rx: /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(dev, pkt_size); if (likely(skb)) { - skb_reserve (skb, NET_IP_ALIGN); /* 16 byte align the IP fields. */ #if RX_BUF_IDX == 3 wrap_copy(skb, rx_ring, ring_offset+4, pkt_size); #else diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 955da733c2a..8b889ab544b 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1433,14 +1433,12 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, packet_size = ((prrs->word1 >> RRS_PKT_SIZE_SHIFT) & RRS_PKT_SIZE_MASK) - 4; /* CRC */ - skb = netdev_alloc_skb(netdev, - packet_size + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(netdev, packet_size); if (skb == NULL) { dev_warn(&pdev->dev, "%s: Memory squeeze," "deferring packet.\n", netdev->name); goto skip_pkt; } - skb_reserve(skb, NET_IP_ALIGN); skb->dev = netdev; memcpy(skb->data, (u8 *)(prrs + 1), packet_size); skb_put(skb, packet_size); diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 00569dc1313..963df502260 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -1864,21 +1864,14 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = netdev_alloc_skb(adapter->netdev, - adapter->rx_buffer_len + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(adapter->netdev, + adapter->rx_buffer_len); if (unlikely(!skb)) { /* Better luck next round */ adapter->netdev->stats.rx_dropped++; break; } - /* - * Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->alloced = 1; buffer_info->skb = skb; buffer_info->length = (u16) adapter->rx_buffer_len; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index ab688862093..0d268075bad 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -409,7 +409,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) if (rxd->status.ok && rxd->status.pkt_size >= 60) { int rx_size = (int)(rxd->status.pkt_size - 4); /* alloc new buffer */ - skb = netdev_alloc_skb(netdev, rx_size + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(netdev, rx_size); if (NULL == skb) { printk(KERN_WARNING "%s: Mem squeeze, deferring packet.\n", @@ -421,7 +421,6 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) netdev->stats.rx_dropped++; break; } - skb_reserve(skb, NET_IP_ALIGN); skb->dev = netdev; memcpy(skb->data, rxd->packet, rx_size); skb_put(skb, rx_size); diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index ba29dc319b3..1f6c5486d71 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -320,16 +320,13 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget) if (len < copybreak) { struct sk_buff *nskb; - nskb = netdev_alloc_skb(dev, len + NET_IP_ALIGN); + nskb = netdev_alloc_skb_ip_align(dev, len); if (!nskb) { /* forget packet, just rearm desc */ priv->stats.rx_dropped++; continue; } - /* since we're copying the data, we can align - * them properly */ - skb_reserve(nskb, NET_IP_ALIGN); dma_sync_single_for_cpu(kdev, desc->address, len, DMA_FROM_DEVICE); memcpy(nskb->data, skb->data, len); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 0e92a1f055a..e0f9d647718 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -756,7 +756,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, if ((adapter->cap == 0x400) && !vtm) vlanf = 0; - skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN); if (!skb) { if (net_ratelimit()) dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); @@ -764,8 +764,6 @@ static void be_rx_compl_process(struct be_adapter *adapter, return; } - skb_reserve(skb, NET_IP_ALIGN); - skb_fill_rx_data(adapter, skb, rxcp); if (do_pkt_csum(rxcp, adapter->rx_csum)) diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 61f9da2b494..67822238940 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -380,9 +380,8 @@ static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv, return NULL; } - skb = netdev_alloc_skb(priv->dev, CPMAC_SKB_SIZE); + skb = netdev_alloc_skb_ip_align(priv->dev, CPMAC_SKB_SIZE); if (likely(skb)) { - skb_reserve(skb, 2); skb_put(desc->skb, desc->datalen); desc->skb->protocol = eth_type_trans(desc->skb, priv->dev); desc->skb->ip_summed = CHECKSUM_NONE; @@ -991,12 +990,11 @@ static int cpmac_open(struct net_device *dev) priv->rx_head = &priv->desc_ring[CPMAC_QUEUES]; for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) { - skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE); + skb = netdev_alloc_skb_ip_align(dev, CPMAC_SKB_SIZE); if (unlikely(!skb)) { res = -ENOMEM; goto fail_desc; } - skb_reserve(skb, 2); desc->skb = skb; desc->data_mapping = dma_map_single(&dev->dev, skb->data, CPMAC_SKB_SIZE, diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 7fa7a907f13..ce8fef184f2 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -505,7 +505,8 @@ rio_timer (unsigned long data) entry = np->old_rx % RX_RING_SIZE; /* Dropped packets don't need to re-allocate */ if (np->rx_skbuff[entry] == NULL) { - skb = netdev_alloc_skb (dev, np->rx_buf_sz); + skb = netdev_alloc_skb_ip_align(dev, + np->rx_buf_sz); if (skb == NULL) { np->rx_ring[entry].fraginfo = 0; printk (KERN_INFO @@ -514,8 +515,6 @@ rio_timer (unsigned long data) break; } np->rx_skbuff[entry] = skb; - /* 16 byte align the IP header */ - skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data, np->rx_buf_sz, @@ -576,7 +575,9 @@ alloc_list (struct net_device *dev) /* Allocate the rx buffers */ for (i = 0; i < RX_RING_SIZE; i++) { /* Allocated fixed size of skbuff */ - struct sk_buff *skb = netdev_alloc_skb (dev, np->rx_buf_sz); + struct sk_buff *skb; + + skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz); np->rx_skbuff[i] = skb; if (skb == NULL) { printk (KERN_ERR @@ -584,7 +585,6 @@ alloc_list (struct net_device *dev) dev->name); break; } - skb_reserve (skb, 2); /* 16 byte align the IP header. */ /* Rubicon now supports 40 bits of addressing space. */ np->rx_ring[i].fraginfo = cpu_to_le64 ( pci_map_single ( @@ -871,13 +871,11 @@ receive_packet (struct net_device *dev) PCI_DMA_FROMDEVICE); skb_put (skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; - } else if ((skb = netdev_alloc_skb(dev, pkt_len + 2))) { + } else if ((skb = netdev_alloc_skb_ip_align(dev, pkt_len))) { pci_dma_sync_single_for_cpu(np->pdev, desc_to_dma(desc), np->rx_buf_sz, PCI_DMA_FROMDEVICE); - /* 16 byte align the IP header */ - skb_reserve (skb, 2); skb_copy_to_linear_data (skb, np->rx_skbuff[entry]->data, pkt_len); @@ -907,7 +905,7 @@ receive_packet (struct net_device *dev) struct sk_buff *skb; /* Dropped packets don't need to re-allocate */ if (np->rx_skbuff[entry] == NULL) { - skb = netdev_alloc_skb(dev, np->rx_buf_sz); + skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz); if (skb == NULL) { np->rx_ring[entry].fraginfo = 0; printk (KERN_INFO @@ -917,8 +915,6 @@ receive_packet (struct net_device *dev) break; } np->rx_skbuff[entry] = skb; - /* 16 byte align the IP header */ - skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data, np->rx_buf_sz, diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 679965c2bb8..ff83efd47b0 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1839,11 +1839,10 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx) #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) { - if (!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN))) + if (!(rx->skb = netdev_alloc_skb_ip_align(nic->netdev, RFD_BUF_LEN))) return -ENOMEM; - /* Align, init, and map the RFD. */ - skb_reserve(rx->skb, NET_IP_ALIGN); + /* Init, and map the RFD. */ skb_copy_to_linear_data(rx->skb, &nic->blank_rfd, sizeof(struct rfd)); rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 6a614148297..c938114a34a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3866,9 +3866,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, * of reassembly being done in the stack */ if (length < copybreak) { struct sk_buff *new_skb = - netdev_alloc_skb(netdev, length + NET_IP_ALIGN); + netdev_alloc_skb_ip_align(netdev, length); if (new_skb) { - skb_reserve(new_skb, NET_IP_ALIGN); skb_copy_to_linear_data_offset(new_skb, -NET_IP_ALIGN, (skb->data - @@ -3937,9 +3936,7 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info; struct sk_buff *skb; unsigned int i; - unsigned int bufsz = 256 - - 16 /*for skb_reserve */ - - NET_IP_ALIGN; + unsigned int bufsz = 256 - 16 /*for skb_reserve */ ; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; @@ -3951,7 +3948,7 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, goto check_page; } - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); if (unlikely(!skb)) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; @@ -3964,7 +3961,7 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, DPRINTK(PROBE, ERR, "skb align check failed: %u bytes " "at %p\n", bufsz, skb->data); /* Try again, without freeing the previous */ - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); /* Failed allocation, critical failure */ if (!skb) { dev_kfree_skb(oldskb); @@ -3982,12 +3979,6 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, /* Use new allocation */ dev_kfree_skb(oldskb); } - /* Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; check_page: @@ -4044,7 +4035,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info; struct sk_buff *skb; unsigned int i; - unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; + unsigned int bufsz = adapter->rx_buffer_len; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; @@ -4056,7 +4047,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, goto map_skb; } - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); if (unlikely(!skb)) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; @@ -4069,7 +4060,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes " "at %p\n", bufsz, skb->data); /* Try again, without freeing the previous */ - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); /* Failed allocation, critical failure */ if (!skb) { dev_kfree_skb(oldskb); @@ -4088,12 +4079,6 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, /* Use new allocation */ dev_kfree_skb(oldskb); } - /* Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; map_skb: diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 21af3984e5c..376924804f3 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -167,7 +167,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info; struct sk_buff *skb; unsigned int i; - unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; + unsigned int bufsz = adapter->rx_buffer_len; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; @@ -179,20 +179,13 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, goto map_skb; } - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); if (!skb) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; break; } - /* - * Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; map_skb: buffer_info->dma = pci_map_single(pdev, skb->data, @@ -284,21 +277,14 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, cpu_to_le64(ps_page->dma); } - skb = netdev_alloc_skb(netdev, - adapter->rx_ps_bsize0 + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(netdev, + adapter->rx_ps_bsize0); if (!skb) { adapter->alloc_rx_buff_failed++; break; } - /* - * Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; buffer_info->dma = pci_map_single(pdev, skb->data, adapter->rx_ps_bsize0, @@ -359,9 +345,7 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info; struct sk_buff *skb; unsigned int i; - unsigned int bufsz = 256 - - 16 /* for skb_reserve */ - - NET_IP_ALIGN; + unsigned int bufsz = 256 - 16 /* for skb_reserve */; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; @@ -373,19 +357,13 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, goto check_page; } - skb = netdev_alloc_skb(netdev, bufsz); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); if (unlikely(!skb)) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; break; } - /* Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; check_page: /* allocate a new page if necessary */ @@ -513,9 +491,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, */ if (length < copybreak) { struct sk_buff *new_skb = - netdev_alloc_skb(netdev, length + NET_IP_ALIGN); + netdev_alloc_skb_ip_align(netdev, length); if (new_skb) { - skb_reserve(new_skb, NET_IP_ALIGN); skb_copy_to_linear_data_offset(new_skb, -NET_IP_ALIGN, (skb->data - diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 41bd7aeafd8..7f8fcc2fa74 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -447,7 +447,9 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, max_index_mask = q_skba->len - 1; for (i = 0; i < fill_wqes; i++) { u64 tmp_addr; - struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); + struct sk_buff *skb; + + skb = netdev_alloc_skb_ip_align(dev, packet_size); if (!skb) { q_skba->os_skbs = fill_wqes - i; if (q_skba->os_skbs == q_skba->len - 2) { @@ -457,7 +459,6 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, } break; } - skb_reserve(skb, NET_IP_ALIGN); skb_arr[index] = skb; tmp_addr = ehea_map_vaddr(skb->data); @@ -500,7 +501,7 @@ static int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes) { return ehea_refill_rq_def(pr, &pr->rq2_skba, 2, nr_of_wqes, EHEA_RWQE2_TYPE, - EHEA_RQ2_PKT_SIZE + NET_IP_ALIGN); + EHEA_RQ2_PKT_SIZE); } @@ -508,7 +509,7 @@ static int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes) { return ehea_refill_rq_def(pr, &pr->rq3_skba, 3, nr_of_wqes, EHEA_RWQE3_TYPE, - EHEA_MAX_PACKET_SIZE + NET_IP_ALIGN); + EHEA_MAX_PACKET_SIZE); } static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num) diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index d69d52ed772..f875751af15 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -870,19 +870,6 @@ static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) dev_kfree_skb_any(buf->os_buf); } -static inline struct sk_buff *enic_rq_alloc_skb(struct net_device *netdev, - unsigned int size) -{ - struct sk_buff *skb; - - skb = netdev_alloc_skb(netdev, size + NET_IP_ALIGN); - - if (skb) - skb_reserve(skb, NET_IP_ALIGN); - - return skb; -} - static int enic_rq_alloc_buf(struct vnic_rq *rq) { struct enic *enic = vnic_dev_priv(rq->vdev); @@ -892,7 +879,7 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) unsigned int os_buf_index = 0; dma_addr_t dma_addr; - skb = enic_rq_alloc_skb(netdev, len); + skb = netdev_alloc_skb_ip_align(netdev, len); if (!skb) return -ENOMEM; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 34d0c69e67f..0c229a5fa82 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -404,10 +404,10 @@ static int ethoc_rx(struct net_device *dev, int limit) if (ethoc_update_rx_stats(priv, &bd) == 0) { int size = bd.stat >> 16; - struct sk_buff *skb = netdev_alloc_skb(dev, size); + struct sk_buff *skb; size -= 4; /* strip the CRC */ - skb_reserve(skb, 2); /* align TCP/IP header */ + skb = netdev_alloc_skb_ip_align(dev, size); if (likely(skb)) { void *src = phys_to_virt(bd.addr); diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 1d5064a09ac..18bd9fe20d7 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -406,10 +406,9 @@ that case. /* A few values that may be tweaked. */ /* Size of each temporary Rx buffer, calculated as: * 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for - * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum + - * 2 more because we use skb_reserve. + * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum */ -#define PKT_BUF_SZ 1538 +#define PKT_BUF_SZ 1536 /* For now, this is going to be set to the maximum size of an ethernet * packet. Eventually, we may want to make it a variable that is @@ -1151,12 +1150,13 @@ static void hamachi_tx_timeout(struct net_device *dev) } /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz); + struct sk_buff *skb; + + skb = netdev_alloc_skb_ip_align(dev, hmp->rx_buf_sz); hmp->rx_skbuff[i] = skb; if (skb == NULL) break; - skb_reserve(skb, 2); /* 16 byte align the IP header. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | @@ -1195,7 +1195,7 @@ static void hamachi_init_ring(struct net_device *dev) * card. -KDU */ hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ : - (((dev->mtu+26+7) & ~7) + 2 + 16)); + (((dev->mtu+26+7) & ~7) + 16)); /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 428d5047535..2ffe0997b83 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -4934,18 +4934,12 @@ static void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, } if (!buffer_info->skb) { - skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); if (!skb) { adapter->alloc_rx_buff_failed++; goto no_buffers; } - /* Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; buffer_info->dma = pci_map_single(pdev, skb->data, bufsz, diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 91024a3cdad..fad7f348dd1 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -170,18 +170,12 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring, } if (!buffer_info->skb) { - skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(netdev, bufsz); if (!skb) { adapter->alloc_rx_buff_failed++; goto no_buffers; } - /* Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; buffer_info->dma = pci_map_single(pdev, skb->data, bufsz, diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 9f7b5d4172b..63056e7b9e2 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -738,17 +738,12 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry) IPG_DEBUG_MSG("_get_rxbuff\n"); - skb = netdev_alloc_skb(dev, sp->rxsupport_size + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(dev, sp->rxsupport_size); if (!skb) { sp->rx_buff[entry] = NULL; return -ENOMEM; } - /* Adjust the data start location within the buffer to - * align IP address field to a 16 byte boundary. - */ - skb_reserve(skb, NET_IP_ALIGN); - /* Associate the receive buffer with the IPG NIC. */ skb->dev = dev; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index f9f633c134b..1bd0ca1b046 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1972,9 +1972,8 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do) * of reassembly being done in the stack */ if (length < copybreak) { struct sk_buff *new_skb = - netdev_alloc_skb(netdev, length + NET_IP_ALIGN); + netdev_alloc_skb_ip_align(netdev, length); if (new_skb) { - skb_reserve(new_skb, NET_IP_ALIGN); skb_copy_to_linear_data_offset(new_skb, -NET_IP_ALIGN, (skb->data - @@ -2057,20 +2056,13 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter, int cleaned_count) goto map_skb; } - skb = netdev_alloc_skb(netdev, adapter->rx_buffer_len - + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(netdev, adapter->rx_buffer_len); if (unlikely(!skb)) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; break; } - /* Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; map_skb: diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index eb3abd79e4e..4c8a4491970 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -616,22 +616,14 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, if (!bi->skb) { struct sk_buff *skb; - skb = netdev_alloc_skb(adapter->netdev, - (rx_ring->rx_buf_len + - NET_IP_ALIGN)); + skb = netdev_alloc_skb_ip_align(adapter->netdev, + rx_ring->rx_buf_len); if (!skb) { adapter->alloc_rx_buff_failed++; goto no_buffers; } - /* - * Make buffer alignment 2 beyond a 16 byte boundary - * this will result in a 16 byte aligned IP header after - * the 14 byte MAC header is removed - */ - skb_reserve(skb, NET_IP_ALIGN); - bi->skb = skb; bi->dma = pci_map_single(pdev, skb->data, rx_ring->rx_buf_len, diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 127243461a5..6baf3c94b3e 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -108,9 +108,8 @@ static int ixpdev_rx(struct net_device *dev, int processed, int budget) if (unlikely(!netif_running(nds[desc->channel]))) goto err; - skb = netdev_alloc_skb(dev, desc->pkt_length + 2); + skb = netdev_alloc_skb_ip_align(dev, desc->pkt_length); if (likely(skb != NULL)) { - skb_reserve(skb, 2); skb_copy_to_linear_data(skb, buf, desc->pkt_length); skb_put(skb, desc->pkt_length); skb->protocol = eth_type_trans(skb, nds[desc->channel]); diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 03199fa1000..a07a5972b57 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -400,7 +400,7 @@ static int korina_rx(struct net_device *dev, int limit) dma_cache_inv((unsigned long)pkt_buf, pkt_len - 4); /* Malloc up new buffer. */ - skb_new = netdev_alloc_skb(dev, KORINA_RBSIZE + 2); + skb_new = netdev_alloc_skb_ip_align(dev, KORINA_RBSIZE); if (!skb_new) break; @@ -417,9 +417,6 @@ static int korina_rx(struct net_device *dev, int limit) if (devcs & ETH_RX_MP) dev->stats.multicast++; - /* 16 bit align */ - skb_reserve(skb_new, 2); - lp->rx_skb[lp->rx_next_done] = skb_new; } diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 99e954167fa..5c45cb58d02 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -357,7 +357,7 @@ static void ks8842_rx_frame(struct net_device *netdev, /* check the status */ if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { - struct sk_buff *skb = netdev_alloc_skb(netdev, len + 2); + struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len); dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n", __func__, len); @@ -369,9 +369,6 @@ static void ks8842_rx_frame(struct net_device *netdev, if (status & RXSR_MULTICAST) netdev->stats.multicast++; - /* Align socket buffer in 4-byte boundary for - better performance. */ - skb_reserve(skb, 2); data = (u32 *)skb_put(skb, len); ks8842_select_bank(adapter, 17); diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 51e11c3e53e..5b24c67de25 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -470,11 +470,11 @@ static inline int init_rx_bufs(struct net_device *dev) for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) { dma_addr_t dma_addr; - struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4); + struct sk_buff *skb; + skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ); if (skb == NULL) return -1; - skb_reserve(skb, 2); dma_addr = dma_map_single(dev->dev.parent, skb->data, PKT_BUF_SZ, DMA_FROM_DEVICE); rbd->v_next = rbd+1; @@ -697,12 +697,12 @@ static inline int i596_rx(struct net_device *dev) (dma_addr_t)SWAP32(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); /* Get fresh skbuff to replace filled one. */ - newskb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4); + newskb = netdev_alloc_skb_ip_align(dev, + PKT_BUF_SZ); if (newskb == NULL) { skb = NULL; /* drop pkt */ goto memory_squeeze; } - skb_reserve(newskb, 2); /* Pass up the skb already on the Rx ring. */ skb_put(skb, pkt_len); @@ -716,7 +716,7 @@ static inline int i596_rx(struct net_device *dev) rbd->b_data = SWAP32(dma_addr); DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd)); } else - skb = netdev_alloc_skb(dev, pkt_len + 2); + skb = netdev_alloc_skb_ip_align(dev, pkt_len); memory_squeeze: if (skb == NULL) { /* XXX tulip.c can defer packets here!! */ @@ -730,7 +730,6 @@ memory_squeeze: dma_sync_single_for_cpu(dev->dev.parent, (dma_addr_t)SWAP32(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); - skb_reserve(skb, 2); memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len); dma_sync_single_for_device(dev->dev.parent, (dma_addr_t)SWAP32(rbd->b_data), diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 50c6a3cfe43..97b170448ce 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3555,13 +3555,12 @@ static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff, if (pkt_size >= rx_copybreak) goto out; - skb = netdev_alloc_skb(tp->dev, pkt_size + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size); if (!skb) goto out; pci_dma_sync_single_for_cpu(tp->pci_dev, addr, pkt_size, PCI_DMA_FROMDEVICE); - skb_reserve(skb, NET_IP_ALIGN); skb_copy_from_linear_data(*sk_buff, skb->data, pkt_size); *sk_buff = skb; done = true; diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 8d6030022d1..b7e0eb40a8b 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -793,7 +793,7 @@ static void _sc92031_rx_tasklet(struct net_device *dev) rx_len -= rx_size_align + 4; - skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(dev, pkt_size); if (unlikely(!skb)) { if (printk_ratelimit()) printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n", @@ -801,8 +801,6 @@ static void _sc92031_rx_tasklet(struct net_device *dev) goto next; } - skb_reserve(skb, NET_IP_ALIGN); - if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) { memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset), rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset); diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index f4dfd1f679a..6b364a6c6c6 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -365,11 +365,10 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp } skb_reserve(newskb, 2); } else { - skb = netdev_alloc_skb(dev, len + 2); - if (skb) { - skb_reserve(skb, 2); + skb = netdev_alloc_skb_ip_align(dev, len); + if (skb) skb_copy_to_linear_data(skb, rd->skb->data, len); - } + newskb = rd->skb; } memory_squeeze: diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 7cc9898f4e0..31233b4c44a 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -536,13 +536,12 @@ static bool sis190_try_rx_copy(struct sis190_private *tp, if (pkt_size >= rx_copybreak) goto out; - skb = netdev_alloc_skb(tp->dev, pkt_size + 2); + skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size); if (!skb) goto out; pci_dma_sync_single_for_cpu(tp->pci_dev, addr, tp->rx_buf_sz, PCI_DMA_FROMDEVICE); - skb_reserve(skb, 2); skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size); *sk_buff = skb; done = true; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 01f6811f132..be28ebb3811 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3070,11 +3070,10 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, goto error; if (len < RX_COPY_THRESHOLD) { - skb = netdev_alloc_skb(dev, len + 2); + skb = netdev_alloc_skb_ip_align(dev, len); if (!skb) goto resubmit; - skb_reserve(skb, 2); pci_dma_sync_single_for_cpu(skge->hw->pdev, pci_unmap_addr(e, mapaddr), len, PCI_DMA_FROMDEVICE); @@ -3085,11 +3084,11 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, skge_rx_reuse(e, skge->rx_buf_size); } else { struct sk_buff *nskb; - nskb = netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN); + + nskb = netdev_alloc_skb_ip_align(dev, skge->rx_buf_size); if (!nskb) goto resubmit; - skb_reserve(nskb, NET_IP_ALIGN); pci_unmap_single(skge->hw->pdev, pci_unmap_addr(e, mapaddr), pci_unmap_len(e, maplen), diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2ab5c39f33c..3a449d012d4 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2191,9 +2191,8 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2, { struct sk_buff *skb; - skb = netdev_alloc_skb(sky2->netdev, length + 2); + skb = netdev_alloc_skb_ip_align(sky2->netdev, length); if (likely(skb)) { - skb_reserve(skb, 2); pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr, length, PCI_DMA_FROMDEVICE); skb_copy_from_linear_data(re->skb, skb->data, length); diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 3d31b47332b..16f23f84920 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1549,7 +1549,8 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) if (tmpCStat & TLAN_CSTAT_EOC) eoc = 1; - new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + new_skb = netdev_alloc_skb_ip_align(dev, + TLAN_MAX_FRAME_SIZE + 5); if ( !new_skb ) goto drop_and_reuse; @@ -1563,7 +1564,6 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - skb_reserve( new_skb, NET_IP_ALIGN ); head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, @@ -1967,13 +1967,12 @@ static void TLan_ResetLists( struct net_device *dev ) list->cStat = TLAN_CSTAT_READY; list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5); if ( !skb ) { pr_err("TLAN: out of memory for received data.\n" ); break; } - skb_reserve( skb, NET_IP_ALIGN ); list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, TLAN_MAX_FRAME_SIZE, diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 7030bd5e984..a69c4a48bab 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -802,13 +802,11 @@ static int tsi108_refill_rx(struct net_device *dev, int budget) int rx = data->rxhead; struct sk_buff *skb; - data->rxskbs[rx] = skb = netdev_alloc_skb(dev, - TSI108_RXBUF_SIZE + 2); + skb = netdev_alloc_skb_ip_align(dev, TSI108_RXBUF_SIZE); + data->rxskbs[rx] = skb; if (!skb) break; - skb_reserve(skb, 2); /* Align the data on a 4-byte boundary. */ - data->rxring[rx].buf0 = dma_map_single(NULL, skb->data, TSI108_RX_SKB_SIZE, DMA_FROM_DEVICE); @@ -1356,7 +1354,7 @@ static int tsi108_open(struct net_device *dev) for (i = 0; i < TSI108_RXRING_LEN; i++) { struct sk_buff *skb; - skb = netdev_alloc_skb(dev, TSI108_RXBUF_SIZE + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(dev, TSI108_RXBUF_SIZE); if (!skb) { /* Bah. No memory for now, but maybe we'll get * some more later. @@ -1370,8 +1368,6 @@ static int tsi108_open(struct net_device *dev) } data->rxskbs[i] = skb; - /* Align the payload on a 4-byte boundary */ - skb_reserve(skb, 2); data->rxskbs[i] = skb; data->rxring[i].buf0 = virt_to_phys(data->rxskbs[i]->data); data->rxring[i].misc = TSI108_RX_OWN | TSI108_RX_INT; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 1fd70583be4..4535e89dfff 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1484,15 +1484,15 @@ static int rhine_rx(struct net_device *dev, int limit) } } } else { - struct sk_buff *skb; + struct sk_buff *skb = NULL; /* Length should omit the CRC */ int pkt_len = data_size - 4; /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN)) != NULL) { - skb_reserve(skb, NET_IP_ALIGN); /* 16 byte align the IP header */ + if (pkt_len < rx_copybreak) + skb = netdev_alloc_skb_ip_align(dev, pkt_len); + if (skb) { pci_dma_sync_single_for_cpu(rp->pdev, rp->rx_skbuff_dma[entry], rp->rx_buf_sz, diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index e04e5bee005..144db6395c9 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1949,10 +1949,9 @@ static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, if (pkt_size < rx_copybreak) { struct sk_buff *new_skb; - new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2); + new_skb = netdev_alloc_skb_ip_align(vptr->dev, pkt_size); if (new_skb) { new_skb->ip_summed = rx_skb[0]->ip_summed; - skb_reserve(new_skb, 2); skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size); *rx_skb = new_skb; ret = 0; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 8d009760277..556512dc607 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -283,13 +283,12 @@ static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp) do { struct skb_vnet_hdr *hdr; - skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN); if (unlikely(!skb)) { oom = true; break; } - skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, MAX_PACKET_LEN); hdr = skb_vnet_hdr(skb); @@ -344,14 +343,12 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp) do { skb_frag_t *f; - skb = netdev_alloc_skb(vi->dev, GOOD_COPY_LEN + NET_IP_ALIGN); + skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN); if (unlikely(!skb)) { oom = true; break; } - skb_reserve(skb, NET_IP_ALIGN); - f = &skb_shinfo(skb)->frags[0]; f->page = get_a_page(vi, gfp); if (!f->page) { diff --git a/net/core/dev.c b/net/core/dev.c index 510ff205d5d..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); -- cgit v1.2.3 From f14001fcd7bd03983c872810a3b11af4148bae72 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 14 Oct 2009 00:48:27 +0000 Subject: Phonet: deliver broadcast packets to broadcast sockets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/net/phonet/phonet.h | 1 + net/phonet/af_phonet.c | 6 ++++++ net/phonet/socket.c | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+) (limited to 'net') diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h index d43f71b5ec0..fdb05fa0346 100644 --- a/include/net/phonet/phonet.h +++ b/include/net/phonet/phonet.h @@ -47,6 +47,7 @@ static inline struct pn_sock *pn_sk(struct sock *sk) extern const struct proto_ops phonet_dgram_ops; struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa); +void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb); void phonet_get_local_port_range(int *min, int *max); void pn_sock_hash(struct sock *sk); void pn_sock_unhash(struct sock *sk); diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index c711d58b4bb..b113fe00c15 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -369,6 +369,12 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, pn_skb_get_dst_sockaddr(skb, &sa); + /* check if this is broadcasted */ + if (pn_sockaddr_get_addr(&sa) == PNADDR_BROADCAST) { + pn_deliver_sock_broadcast(net, skb); + goto out; + } + /* check if we are the destination */ if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) { /* Phonet packet input */ diff --git a/net/phonet/socket.c b/net/phonet/socket.c index aa5b5a972bf..8c84190f22d 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -94,7 +94,28 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) spin_unlock_bh(&pnsocks.lock); return rval; +} + +/* Deliver a broadcast packet (only in bottom-half) */ +void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb) +{ + struct hlist_node *node; + struct sock *sknode; + + spin_lock(&pnsocks.lock); + sk_for_each(sknode, node, &pnsocks.hlist) { + struct sk_buff *clone; + + if (!net_eq(sock_net(sknode), net)) + continue; + if (!sock_flag(sknode, SOCK_BROADCAST)) + continue; + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) + sk_receive_skb(sknode, clone, 0); + } + spin_unlock(&pnsocks.lock); } void pn_sock_hash(struct sock *sk) -- cgit v1.2.3 From 55748ac0468134a89bc55aed6a9691e320caa8a9 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 14 Oct 2009 00:48:28 +0000 Subject: Phonet: routing table backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Phonet "universe" only has 64 addresses, so we keep a trivial flat routing table. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/net/phonet/pn_dev.h | 5 +++ net/phonet/pn_dev.c | 100 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index 44c923c9e21..87b5d8112e1 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h @@ -47,6 +47,11 @@ u8 phonet_address_get(struct net_device *dev, u8 addr); int phonet_address_lookup(struct net *net, u8 addr); void phonet_address_notify(int event, struct net_device *dev, u8 addr); +int phonet_route_add(struct net_device *dev, u8 daddr); +int phonet_route_del(struct net_device *dev, u8 daddr); +struct net_device *phonet_route_get(struct net *net, u8 daddr); +struct net_device *phonet_route_output(struct net *net, u8 daddr); + #define PN_NO_ADDR 0xff extern const struct file_operations pn_sock_seq_fops; diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 5f42f30dd16..71fffa58778 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -33,8 +33,14 @@ #include #include +struct phonet_routes { + spinlock_t lock; + struct net_device *table[64]; +}; + struct phonet_net { struct phonet_device_list pndevs; + struct phonet_routes routes; }; int phonet_net_id; @@ -154,10 +160,11 @@ int phonet_address_del(struct net_device *dev, u8 addr) } /* Gets a source address toward a destination, through a interface. */ -u8 phonet_address_get(struct net_device *dev, u8 addr) +u8 phonet_address_get(struct net_device *dev, u8 daddr) { struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); struct phonet_device *pnd; + u8 saddr; spin_lock_bh(&pndevs->lock); pnd = __phonet_get(dev); @@ -165,12 +172,26 @@ u8 phonet_address_get(struct net_device *dev, u8 addr) BUG_ON(bitmap_empty(pnd->addrs, 64)); /* Use same source address as destination, if possible */ - if (!test_bit(addr >> 2, pnd->addrs)) - addr = find_first_bit(pnd->addrs, 64) << 2; + if (test_bit(daddr >> 2, pnd->addrs)) + saddr = daddr; + else + saddr = find_first_bit(pnd->addrs, 64) << 2; } else - addr = PN_NO_ADDR; + saddr = PN_NO_ADDR; spin_unlock_bh(&pndevs->lock); - return addr; + + if (saddr == PN_NO_ADDR) { + /* Fallback to another device */ + struct net_device *def_dev; + + def_dev = phonet_device_get(dev_net(dev)); + if (def_dev) { + if (def_dev != dev) + saddr = phonet_address_get(def_dev, daddr); + dev_put(def_dev); + } + } + return saddr; } int phonet_address_lookup(struct net *net, u8 addr) @@ -246,7 +267,7 @@ static struct notifier_block phonet_device_notifier = { /* Per-namespace Phonet devices handling */ static int phonet_init_net(struct net *net) { - struct phonet_net *pnn = kmalloc(sizeof(*pnn), GFP_KERNEL); + struct phonet_net *pnn = kzalloc(sizeof(*pnn), GFP_KERNEL); if (!pnn) return -ENOMEM; @@ -257,6 +278,7 @@ static int phonet_init_net(struct net *net) INIT_LIST_HEAD(&pnn->pndevs.list); spin_lock_init(&pnn->pndevs.lock); + spin_lock_init(&pnn->routes.lock); net_assign_generic(net, phonet_net_id, pnn); return 0; } @@ -300,3 +322,69 @@ void phonet_device_exit(void) unregister_netdevice_notifier(&phonet_device_notifier); unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops); } + +int phonet_route_add(struct net_device *dev, u8 daddr) +{ + struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id); + struct phonet_routes *routes = &pnn->routes; + int err = -EEXIST; + + daddr = daddr >> 2; + spin_lock_bh(&routes->lock); + if (routes->table[daddr] == NULL) { + routes->table[daddr] = dev; + dev_hold(dev); + err = 0; + } + spin_unlock_bh(&routes->lock); + return err; +} + +int phonet_route_del(struct net_device *dev, u8 daddr) +{ + struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id); + struct phonet_routes *routes = &pnn->routes; + int err = -ENOENT; + + daddr = daddr >> 2; + spin_lock_bh(&routes->lock); + if (dev == routes->table[daddr]) { + routes->table[daddr] = NULL; + dev_put(dev); + err = 0; + } + spin_unlock_bh(&routes->lock); + return err; +} + +struct net_device *phonet_route_get(struct net *net, u8 daddr) +{ + struct phonet_net *pnn = net_generic(net, phonet_net_id); + struct phonet_routes *routes = &pnn->routes; + struct net_device *dev; + + ASSERT_RTNL(); /* no need to hold the device */ + + daddr >>= 2; + spin_lock_bh(&routes->lock); + dev = routes->table[daddr]; + spin_unlock_bh(&routes->lock); + return dev; +} + +struct net_device *phonet_route_output(struct net *net, u8 daddr) +{ + struct phonet_net *pnn = net_generic(net, phonet_net_id); + struct phonet_routes *routes = &pnn->routes; + struct net_device *dev; + + spin_lock_bh(&routes->lock); + dev = routes->table[daddr >> 2]; + if (dev) + dev_hold(dev); + spin_unlock_bh(&routes->lock); + + if (!dev) + dev = phonet_device_get(net); /* Default route */ + return dev; +} -- cgit v1.2.3 From f062f41d06575744b9eaf725eef8a5d3b5f5b7ca Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 14 Oct 2009 00:48:29 +0000 Subject: Phonet: routing table Netlink interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/net/phonet/pn_dev.h | 1 + net/phonet/pn_dev.c | 31 +++++++++++ net/phonet/pn_netlink.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) (limited to 'net') diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index 87b5d8112e1..afa7defceb1 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h @@ -49,6 +49,7 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr); int phonet_route_add(struct net_device *dev, u8 daddr); int phonet_route_del(struct net_device *dev, u8 daddr); +void rtm_phonet_notify(int event, struct net_device *dev, u8 dst); struct net_device *phonet_route_get(struct net *net, u8 daddr); struct net_device *phonet_route_output(struct net *net, u8 daddr); diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 71fffa58778..6d64fda1afc 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -240,6 +240,27 @@ static int phonet_device_autoconf(struct net_device *dev) return 0; } +static void phonet_route_autodel(struct net_device *dev) +{ + struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id); + unsigned i; + DECLARE_BITMAP(deleted, 64); + + /* Remove left-over Phonet routes */ + bitmap_zero(deleted, 64); + spin_lock_bh(&pnn->routes.lock); + for (i = 0; i < 64; i++) + if (dev == pnn->routes.table[i]) { + set_bit(i, deleted); + pnn->routes.table[i] = NULL; + dev_put(dev); + } + spin_unlock_bh(&pnn->routes.lock); + for (i = find_first_bit(deleted, 64); i < 64; + i = find_next_bit(deleted, 64, i + 1)) + rtm_phonet_notify(RTM_DELROUTE, dev, i); +} + /* notify Phonet of device events */ static int phonet_device_notify(struct notifier_block *me, unsigned long what, void *arg) @@ -253,6 +274,7 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what, break; case NETDEV_UNREGISTER: phonet_device_destroy(dev); + phonet_route_autodel(dev); break; } return 0; @@ -287,10 +309,19 @@ static void phonet_exit_net(struct net *net) { struct phonet_net *pnn = net_generic(net, phonet_net_id); struct net_device *dev; + unsigned i; rtnl_lock(); for_each_netdev(net, dev) phonet_device_destroy(dev); + + for (i = 0; i < 64; i++) { + dev = pnn->routes.table[i]; + if (dev) { + rtm_phonet_notify(RTM_DELROUTE, dev, i); + dev_put(dev); + } + } rtnl_unlock(); proc_net_remove(net, "phonet"); diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c index d21fd357661..d8f5d3fb9ee 100644 --- a/net/phonet/pn_netlink.c +++ b/net/phonet/pn_netlink.c @@ -29,6 +29,8 @@ #include #include +/* Device address handling */ + static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr, u32 pid, u32 seq, int event); @@ -160,6 +162,131 @@ out: return skb->len; } +/* Routes handling */ + +static int fill_route(struct sk_buff *skb, struct net_device *dev, u8 dst, + u32 pid, u32 seq, int event) +{ + struct rtmsg *rtm; + struct nlmsghdr *nlh; + + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), 0); + if (nlh == NULL) + return -EMSGSIZE; + + rtm = nlmsg_data(nlh); + rtm->rtm_family = AF_PHONET; + rtm->rtm_dst_len = 6; + rtm->rtm_src_len = 0; + rtm->rtm_tos = 0; + rtm->rtm_table = RT_TABLE_MAIN; + rtm->rtm_protocol = RTPROT_STATIC; + rtm->rtm_scope = RT_SCOPE_UNIVERSE; + rtm->rtm_type = RTN_UNICAST; + rtm->rtm_flags = 0; + NLA_PUT_U8(skb, RTA_DST, dst); + NLA_PUT_U32(skb, RTA_OIF, dev->ifindex); + return nlmsg_end(skb, nlh); + +nla_put_failure: + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; +} + +void rtm_phonet_notify(int event, struct net_device *dev, u8 dst) +{ + struct sk_buff *skb; + int err = -ENOBUFS; + + skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + + nla_total_size(1) + nla_total_size(4), GFP_KERNEL); + if (skb == NULL) + goto errout; + err = fill_route(skb, dev, dst, 0, 0, event); + if (err < 0) { + WARN_ON(err == -EMSGSIZE); + kfree_skb(skb); + goto errout; + } + rtnl_notify(skb, dev_net(dev), 0, + RTNLGRP_PHONET_ROUTE, NULL, GFP_KERNEL); + return; +errout: + if (err < 0) + rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_ROUTE, err); +} + +static const struct nla_policy rtm_phonet_policy[RTA_MAX+1] = { + [RTA_DST] = { .type = NLA_U8 }, + [RTA_OIF] = { .type = NLA_U32 }, +}; + +static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr) +{ + struct net *net = sock_net(skb->sk); + struct nlattr *tb[RTA_MAX+1]; + struct net_device *dev; + struct rtmsg *rtm; + int err; + u8 dst; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ASSERT_RTNL(); + + err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_phonet_policy); + if (err < 0) + return err; + + rtm = nlmsg_data(nlh); + if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_type != RTN_UNICAST) + return -EINVAL; + if (tb[RTA_DST] == NULL || tb[RTA_OIF] == NULL) + return -EINVAL; + dst = nla_get_u8(tb[RTA_DST]); + if (dst & 3) /* Phonet addresses only have 6 high-order bits */ + return -EINVAL; + + dev = __dev_get_by_index(net, nla_get_u32(tb[RTA_OIF])); + if (dev == NULL) + return -ENODEV; + + if (nlh->nlmsg_type == RTM_NEWROUTE) + err = phonet_route_add(dev, dst); + else + err = phonet_route_del(dev, dst); + if (!err) + rtm_phonet_notify(nlh->nlmsg_type, dev, dst); + return err; +} + +static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + u8 addr, addr_idx = 0, addr_start_idx = cb->args[0]; + + for (addr = 0; addr < 64; addr++) { + struct net_device *dev; + + dev = phonet_route_get(net, addr << 2); + if (!dev) + continue; + + if (addr_idx++ < addr_start_idx) + continue; + if (fill_route(skb, dev, addr << 2, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, RTM_NEWROUTE)) + goto out; + } + +out: + cb->args[0] = addr_idx; + cb->args[1] = 0; + + return skb->len; +} + int __init phonet_netlink_register(void) { int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL); @@ -169,5 +296,8 @@ int __init phonet_netlink_register(void) /* Further __rtnl_register() cannot fail */ __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL); __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit); + __rtnl_register(PF_PHONET, RTM_NEWROUTE, route_doit, NULL); + __rtnl_register(PF_PHONET, RTM_DELROUTE, route_doit, NULL); + __rtnl_register(PF_PHONET, RTM_GETROUTE, NULL, route_dumpit); return 0; } -- cgit v1.2.3 From aa6c45f32f7db292f8f6a76d7b39c19007d6a456 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 14 Oct 2009 00:48:30 +0000 Subject: Phonet: route outgoing packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/af_phonet.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index b113fe00c15..cc2eef169a8 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -190,9 +190,8 @@ static int pn_send(struct sk_buff *skb, struct net_device *dev, skb->priority = 0; skb->dev = dev; - if (pn_addr(src) == pn_addr(dst)) { + if (skb->pkt_type == PACKET_LOOPBACK) { skb_reset_mac_header(skb); - skb->pkt_type = PACKET_LOOPBACK; skb_orphan(skb); if (irq) netif_rx(skb); @@ -222,6 +221,9 @@ static int pn_raw_send(const void *data, int len, struct net_device *dev, if (skb == NULL) return -ENOMEM; + if (phonet_address_lookup(dev_net(dev), pn_addr(dst)) == 0) + skb->pkt_type = PACKET_LOOPBACK; + skb_reserve(skb, MAX_PHONET_HEADER); __skb_put(skb, len); skb_copy_to_linear_data(skb, data, len); @@ -235,6 +237,7 @@ static int pn_raw_send(const void *data, int len, struct net_device *dev, int pn_skb_send(struct sock *sk, struct sk_buff *skb, const struct sockaddr_pn *target) { + struct net *net = sock_net(sk); struct net_device *dev; struct pn_sock *pn = pn_sk(sk); int err; @@ -243,9 +246,13 @@ int pn_skb_send(struct sock *sk, struct sk_buff *skb, err = -EHOSTUNREACH; if (sk->sk_bound_dev_if) - dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); - else - dev = phonet_device_get(sock_net(sk)); + dev = dev_get_by_index(net, sk->sk_bound_dev_if); + else if (phonet_address_lookup(net, daddr) == 0) { + dev = phonet_device_get(net); + skb->pkt_type = PACKET_LOOPBACK; + } else + dev = phonet_route_output(net, daddr); + if (!dev || !(dev->flags & IFF_UP)) goto drop; -- cgit v1.2.3 From 86a0a1e52d0918125ffc21475537a032f9a71d7c Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 14 Oct 2009 00:48:31 +0000 Subject: Phonet: forward incoming packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/af_phonet.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'net') diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index cc2eef169a8..66737aa995e 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -394,6 +394,38 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, send_obj_unreachable(skb); send_reset_indications(skb); } + } else if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) + goto out; /* Race between address deletion and loopback */ + else { + /* Phonet packet routing */ + struct net_device *out_dev; + + out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa)); + if (!out_dev) { + LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X\n", + pn_sockaddr_get_addr(&sa)); + goto out; + } + + __skb_push(skb, sizeof(struct phonethdr)); + skb->dev = out_dev; + if (out_dev == dev) { + LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s\n", + pn_sockaddr_get_addr(&sa), dev->name); + goto out_dev; + } + /* Some drivers (e.g. TUN) do not allocate HW header space */ + if (skb_cow_head(skb, out_dev->hard_header_len)) + goto out_dev; + + if (dev_hard_header(skb, out_dev, ETH_P_PHONET, NULL, NULL, + skb->len) < 0) + goto out_dev; + dev_queue_xmit(skb); + dev_put(out_dev); + return NET_RX_SUCCESS; +out_dev: + dev_put(out_dev); } out: -- cgit v1.2.3 From 766e9037cc139ee25ed93ee5ad11e1450c4b99f6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 14 Oct 2009 20:40:11 -0700 Subject: net: sk_drops consolidation sock_queue_rcv_skb() can update sk_drops itself, removing need for callers to take care of it. This is more consistent since sock_queue_rcv_skb() also reads sk_drops when queueing a skb. This adds sk_drops managment to many protocols that not cared yet. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 15 +++++++-------- net/ieee802154/dgram.c | 1 - net/ieee802154/raw.c | 1 - net/ipv4/raw.c | 1 - net/ipv4/udp.c | 19 ++++++++----------- net/ipv6/raw.c | 3 +-- net/ipv6/udp.c | 6 ++---- net/phonet/datagram.c | 6 ++---- net/phonet/pep.c | 2 -- 9 files changed, 20 insertions(+), 34 deletions(-) (limited to 'net') diff --git a/net/core/sock.c b/net/core/sock.c index 43ca2c99539..38713aa3faf 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -274,7 +274,7 @@ static void sock_disable_timestamp(struct sock *sk, int flag) int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { - int err = 0; + int err; int skb_len; unsigned long flags; struct sk_buff_head *list = &sk->sk_receive_queue; @@ -284,17 +284,17 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) */ if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= (unsigned)sk->sk_rcvbuf) { - err = -ENOMEM; - goto out; + atomic_inc(&sk->sk_drops); + return -ENOMEM; } err = sk_filter(sk, skb); if (err) - goto out; + return err; if (!sk_rmem_schedule(sk, skb->truesize)) { - err = -ENOBUFS; - goto out; + atomic_inc(&sk->sk_drops); + return -ENOBUFS; } skb->dev = NULL; @@ -314,8 +314,7 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) if (!sock_flag(sk, SOCK_DEAD)) sk->sk_data_ready(sk, skb_len); -out: - return err; + return 0; } EXPORT_SYMBOL(sock_queue_rcv_skb); diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 25ad956a39d..9aac5aee157 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -318,7 +318,6 @@ out: static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) { if (sock_queue_rcv_skb(sk, skb) < 0) { - atomic_inc(&sk->sk_drops); kfree_skb(skb); return NET_RX_DROP; } diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 769c8d138fc..9c9b85c0003 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -206,7 +206,6 @@ out: static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) { if (sock_queue_rcv_skb(sk, skb) < 0) { - atomic_inc(&sk->sk_drops); kfree_skb(skb); return NET_RX_DROP; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index f18172b0761..39e2a6b8752 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -292,7 +292,6 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb) /* Charge it to the socket. */ if (sock_queue_rcv_skb(sk, skb) < 0) { - atomic_inc(&sk->sk_drops); kfree_skb(skb); return NET_RX_DROP; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ee61b3fc4ca..45a8a7e374d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1063,25 +1063,22 @@ EXPORT_SYMBOL(udp_lib_unhash); static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { - int is_udplite = IS_UDPLITE(sk); - int rc; + int rc = sock_queue_rcv_skb(sk, skb); + + if (rc < 0) { + int is_udplite = IS_UDPLITE(sk); - if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) { + if (rc == -ENOMEM) UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, is_udplite); - atomic_inc(&sk->sk_drops); - } - goto drop; + UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); + kfree_skb(skb); + return -1; } return 0; -drop: - UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; } /* returns: diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d8375bc7f2d..fd737efed96 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -381,8 +381,7 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) } /* Charge it to the socket. */ - if (sock_queue_rcv_skb(sk,skb)<0) { - atomic_inc(&sk->sk_drops); + if (sock_queue_rcv_skb(sk, skb) < 0) { kfree_skb(skb); return NET_RX_DROP; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 1f8e2afa449..b86425b7ea2 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -385,13 +385,11 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) goto drop; } - if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { + if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) { + if (rc == -ENOMEM) UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, is_udplite); - atomic_inc(&sk->sk_drops); - } goto drop; } diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c index ef5c75c372e..67f072e94d0 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c @@ -159,11 +159,9 @@ out_nofree: static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb) { int err = sock_queue_rcv_skb(sk, skb); - if (err < 0) { + + if (err < 0) kfree_skb(skb); - if (err == -ENOMEM) - atomic_inc(&sk->sk_drops); - } return err ? NET_RX_DROP : NET_RX_SUCCESS; } diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 5f32d217535..cbaa1d67d77 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -360,8 +360,6 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) err = sock_queue_rcv_skb(sk, skb); if (!err) return 0; - if (err == -ENOMEM) - atomic_inc(&sk->sk_drops); break; } -- cgit v1.2.3 From 21912d1ca2546ca96743c91d5a4125aef2d9df70 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Thu, 15 Oct 2009 12:29:14 -0700 Subject: Phonet: hold socket before giving it to sk_deliver_skb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/phonet/socket.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 8c84190f22d..0412beb59a0 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -112,8 +112,10 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb) continue; clone = skb_clone(skb, GFP_ATOMIC); - if (clone) + if (clone) { + sock_hold(sknode); sk_receive_skb(sknode, clone, 0); + } } spin_unlock(&pnsocks.lock); } -- cgit v1.2.3 From 49f5eba7575e6dfb146c5e24623d50200ce23ff1 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Wed, 14 Oct 2009 22:54:55 +0000 Subject: af_iucv: use sk functions to modify sk->sk_ack_backlog Instead of modifying sk->sk_ack_backlog directly, use respective socket functions. Signed-off-by: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 004134b60d8..73ea01be68e 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -536,7 +536,7 @@ void iucv_accept_enqueue(struct sock *parent, struct sock *sk) list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q); spin_unlock_irqrestore(&par->accept_q_lock, flags); iucv_sk(sk)->parent = parent; - parent->sk_ack_backlog++; + sk_acceptq_added(parent); } void iucv_accept_unlink(struct sock *sk) @@ -547,7 +547,7 @@ void iucv_accept_unlink(struct sock *sk) spin_lock_irqsave(&par->accept_q_lock, flags); list_del_init(&iucv_sk(sk)->accept_q); spin_unlock_irqrestore(&par->accept_q_lock, flags); - iucv_sk(sk)->parent->sk_ack_backlog--; + sk_acceptq_removed(iucv_sk(sk)->parent); iucv_sk(sk)->parent = NULL; sock_put(sk); } -- cgit v1.2.3 From 9a4ff8d417e4ef2eeecb4a4433e3dbd8251aae5e Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Wed, 14 Oct 2009 22:54:56 +0000 Subject: af_iucv: remove duplicate sock_set_flag Remove duplicate sock_set_flag(sk, SOCK_ZAPPED) in iucv_sock_close, which has been overlooked in September-commit 7514bab04e567c9408fe0facbde4277f09d5eb74. Cc: Hendrik Brueckner Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 73ea01be68e..3aebabb158a 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -428,7 +428,6 @@ static void iucv_sock_close(struct sock *sk) break; default: - sock_set_flag(sk, SOCK_ZAPPED); /* nothing to do here */ break; } -- cgit v1.2.3 From 93860b08e31a3202b6e67e386811545e719a0165 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Wed, 14 Oct 2009 19:54:53 +0000 Subject: genetlink: Optimize genl_register_family() genl_register_family() doesn't need to call genl_family_find_byid when GENL_ID_GENERATE is passed during register. Patch on net-next-2.6, compile and reboot testing only. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 44ff3f3810f..ddfdb7d2e02 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -374,11 +374,6 @@ int genl_register_family(struct genl_family *family) goto errout_locked; } - if (genl_family_find_byid(family->id)) { - err = -EEXIST; - goto errout_locked; - } - if (family->id == GENL_ID_GENERATE) { u16 newid = genl_generate_id(); @@ -388,6 +383,9 @@ int genl_register_family(struct genl_family *family) } family->id = newid; + } else if (genl_family_find_byid(family->id)) { + err = -EEXIST; + goto errout_locked; } if (family->maxattr) { -- cgit v1.2.3 From 988ade6b8e27e79311812f83a87b5cea11fabcd7 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Wed, 14 Oct 2009 19:55:07 +0000 Subject: genetlink: Optimize and one bug fix in genl_generate_id() 1. GENL_MIN_ID is a valid id -> no need to start at GENL_MIN_ID + 1. 2. Avoid going through the ids two times: If we start at GENL_MIN_ID+1 (*or bigger*) and all ids are over!, the code iterates through the list twice (*or lesser*). 3. Simplify code - no need to start at idx=0 which gets reset to GENL_MIN_ID. Patch on net-next-2.6. Reboot test shows that first id passed to genl_register_family was 16, next two were GENL_ID_GENERATE and genl_generate_id returned 17 & 18 (user level testing of same code shows expected values across entire range of MIN/MAX). Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index ddfdb7d2e02..d07ecda0a92 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -97,25 +97,17 @@ static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) */ static inline u16 genl_generate_id(void) { - static u16 id_gen_idx; - int overflowed = 0; + static u16 id_gen_idx = GENL_MIN_ID; + int i; - do { - if (id_gen_idx == 0) + for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { + if (!genl_family_find_byid(id_gen_idx)) + return id_gen_idx; + if (++id_gen_idx > GENL_MAX_ID) id_gen_idx = GENL_MIN_ID; + } - if (++id_gen_idx > GENL_MAX_ID) { - if (!overflowed) { - overflowed = 1; - id_gen_idx = 0; - continue; - } else - return 0; - } - - } while (genl_family_find_byid(id_gen_idx)); - - return id_gen_idx; + return 0; } static struct genl_multicast_group notify_grp; -- cgit v1.2.3 From c720c7e8383aff1cb219bddf474ed89d850336e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 15 Oct 2009 06:30:45 +0000 Subject: inet: rename some inet_sock fields In order to have better cache layouts of struct sock (separate zones for rx/tx paths), we need this preliminary patch. Goal is to transfert fields used at lookup time in the first read-mostly cache line (inside struct sock_common) and move sk_refcnt to a separate cache line (only written by rx path) This patch adds inet_ prefix to daddr, rcv_saddr, dport, num, saddr, sport and id fields. This allows a future patch to define these fields as macros, like sk_refcnt, without name clashes. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/pppol2tp.c | 22 ++++---- fs/ocfs2/cluster/netdebug.c | 8 +-- include/linux/ipv6.h | 2 +- include/net/inet6_hashtables.h | 4 +- include/net/inet_hashtables.h | 12 ++--- include/net/inet_sock.h | 36 ++++++------- include/net/inet_timewait_sock.h | 2 +- include/net/ip.h | 12 ++--- net/dccp/ipv4.c | 40 ++++++++------- net/dccp/ipv6.c | 27 +++++----- net/dccp/output.c | 4 +- net/dccp/probe.c | 13 ++--- net/dccp/proto.c | 4 +- net/ipv4/af_inet.c | 62 +++++++++++------------ net/ipv4/datagram.c | 18 +++---- net/ipv4/inet_connection_sock.c | 20 ++++---- net/ipv4/inet_diag.c | 26 +++++----- net/ipv4/inet_hashtables.c | 34 +++++++------ net/ipv4/inet_timewait_sock.c | 12 ++--- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_output.c | 15 +++--- net/ipv4/ip_sockglue.c | 8 +-- net/ipv4/ipmr.c | 2 +- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 8 +-- net/ipv4/raw.c | 30 +++++------ net/ipv4/tcp.c | 4 +- net/ipv4/tcp_ipv4.c | 70 +++++++++++++------------- net/ipv4/tcp_output.c | 4 +- net/ipv4/tcp_probe.c | 11 ++-- net/ipv4/tcp_timer.c | 8 +-- net/ipv4/udp.c | 51 ++++++++++--------- net/ipv6/af_inet6.c | 28 +++++------ net/ipv6/datagram.c | 15 +++--- net/ipv6/inet6_connection_sock.c | 6 +-- net/ipv6/inet6_hashtables.c | 12 ++--- net/ipv6/ip6mr.c | 2 +- net/ipv6/ipv6_sockglue.c | 6 +-- net/ipv6/raw.c | 30 +++++------ net/ipv6/syncookies.c | 2 +- net/ipv6/tcp_ipv6.c | 32 ++++++------ net/ipv6/udp.c | 24 ++++----- net/netfilter/xt_socket.c | 2 +- net/rds/tcp_listen.c | 8 +-- net/sctp/protocol.c | 8 +-- net/sctp/socket.c | 30 +++++------ net/sunrpc/svcsock.c | 8 +-- security/lsm_audit.c | 12 ++--- 47 files changed, 408 insertions(+), 388 deletions(-) (limited to 'net') diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 5910df60c93..849cc9c62c2 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -516,7 +516,7 @@ static inline int pppol2tp_verify_udp_checksum(struct sock *sk, return 0; inet = inet_sk(sk); - psum = csum_tcpudp_nofold(inet->saddr, inet->daddr, ulen, + psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen, IPPROTO_UDP, 0); if ((skb->ip_summed == CHECKSUM_COMPLETE) && @@ -949,8 +949,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh inet = inet_sk(sk_tun); udp_len = hdr_len + sizeof(ppph) + total_len; uh = (struct udphdr *) skb->data; - uh->source = inet->sport; - uh->dest = inet->dport; + uh->source = inet->inet_sport; + uh->dest = inet->inet_dport; uh->len = htons(udp_len); uh->check = 0; skb_put(skb, sizeof(struct udphdr)); @@ -978,7 +978,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); - uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, + uh->check = csum_tcpudp_magic(inet->inet_saddr, + inet->inet_daddr, udp_len, IPPROTO_UDP, csum); if (uh->check == 0) uh->check = CSUM_MANGLED_0; @@ -986,7 +987,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh skb->ip_summed = CHECKSUM_PARTIAL; skb->csum_start = skb_transport_header(skb) - skb->head; skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, + uh->check = ~csum_tcpudp_magic(inet->inet_saddr, + inet->inet_daddr, udp_len, IPPROTO_UDP, 0); } @@ -1136,8 +1138,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) __skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); uh = udp_hdr(skb); - uh->source = inet->sport; - uh->dest = inet->dport; + uh->source = inet->inet_sport; + uh->dest = inet->inet_dport; uh->len = htons(udp_len); uh->check = 0; @@ -1181,7 +1183,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); - uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, + uh->check = csum_tcpudp_magic(inet->inet_saddr, + inet->inet_daddr, udp_len, IPPROTO_UDP, csum); if (uh->check == 0) uh->check = CSUM_MANGLED_0; @@ -1189,7 +1192,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) skb->ip_summed = CHECKSUM_PARTIAL; skb->csum_start = skb_transport_header(skb) - skb->head; skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, + uh->check = ~csum_tcpudp_magic(inet->inet_saddr, + inet->inet_daddr, udp_len, IPPROTO_UDP, 0); } diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c index da794bc07a6..a3f150e52b0 100644 --- a/fs/ocfs2/cluster/netdebug.c +++ b/fs/ocfs2/cluster/netdebug.c @@ -294,10 +294,10 @@ static int sc_seq_show(struct seq_file *seq, void *v) if (sc->sc_sock) { inet = inet_sk(sc->sc_sock->sk); /* the stack's structs aren't sparse endian clean */ - saddr = (__force __be32)inet->saddr; - daddr = (__force __be32)inet->daddr; - sport = (__force __be16)inet->sport; - dport = (__force __be16)inet->dport; + saddr = (__force __be32)inet->inet_saddr; + daddr = (__force __be32)inet->inet_daddr; + sport = (__force __be16)inet->inet_sport; + dport = (__force __be16)inet->inet_dport; } /* XXX sigh, inet-> doesn't have sparse annotation so any diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 56404251248..e0cc9a7db2b 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -505,7 +505,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk) #define INET6_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif)\ (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ - ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ ((__sk)->sk_family == AF_INET6) && \ ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \ ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \ diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index 22c73a77cd9..92838d3a1ab 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h @@ -46,8 +46,8 @@ static inline int inet6_sk_ehashfn(const struct sock *sk) const struct ipv6_pinfo *np = inet6_sk(sk); const struct in6_addr *laddr = &np->rcv_saddr; const struct in6_addr *faddr = &np->daddr; - const __u16 lport = inet->num; - const __be16 fport = inet->dport; + const __u16 lport = inet->inet_num; + const __be16 fport = inet->inet_dport; struct net *net = sock_net(sk); return inet6_ehashfn(net, laddr, lport, faddr, fport); diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 5f11c4a0dac..5b698b3b463 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -241,7 +241,7 @@ static inline int inet_lhashfn(struct net *net, const unsigned short num) static inline int inet_sk_listen_hashfn(const struct sock *sk) { - return inet_lhashfn(sock_net(sk), inet_sk(sk)->num); + return inet_lhashfn(sock_net(sk), inet_sk(sk)->inet_num); } /* Caller must disable local BH processing. */ @@ -301,8 +301,8 @@ typedef __u64 __bitwise __addrpair; #endif /* __BIG_ENDIAN */ #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ - ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ - ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + ((*((__addrpair *)&(inet_sk(__sk)->inet_daddr))) == (__cookie)) && \ + ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ @@ -313,9 +313,9 @@ typedef __u64 __bitwise __addrpair; #define INET_ADDR_COOKIE(__name, __saddr, __daddr) #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ - (inet_sk(__sk)->daddr == (__saddr)) && \ - (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ - ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ + (inet_sk(__sk)->inet_daddr == (__saddr)) && \ + (inet_sk(__sk)->inet_rcv_saddr == (__daddr)) && \ + ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 47004f35cc7..bd4c53f75ac 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -93,14 +93,14 @@ struct rtable; * * @sk - ancestor class * @pinet6 - pointer to IPv6 control block - * @daddr - Foreign IPv4 addr - * @rcv_saddr - Bound local IPv4 addr - * @dport - Destination port - * @num - Local port - * @saddr - Sending source + * @inet_daddr - Foreign IPv4 addr + * @inet_rcv_saddr - Bound local IPv4 addr + * @inet_dport - Destination port + * @inet_num - Local port + * @inet_saddr - Sending source * @uc_ttl - Unicast TTL - * @sport - Source port - * @id - ID counter for DF pkts + * @inet_sport - Source port + * @inet_id - ID counter for DF pkts * @tos - TOS * @mc_ttl - Multicasting TTL * @is_icsk - is this an inet_connection_sock? @@ -115,16 +115,16 @@ struct inet_sock { struct ipv6_pinfo *pinet6; #endif /* Socket demultiplex comparisons on incoming packets. */ - __be32 daddr; - __be32 rcv_saddr; - __be16 dport; - __u16 num; - __be32 saddr; + __be32 inet_daddr; + __be32 inet_rcv_saddr; + __be16 inet_dport; + __u16 inet_num; + __be32 inet_saddr; __s16 uc_ttl; __u16 cmsg_flags; struct ip_options *opt; - __be16 sport; - __u16 id; + __be16 inet_sport; + __u16 inet_id; __u8 tos; __u8 mc_ttl; __u8 pmtudisc; @@ -190,10 +190,10 @@ static inline unsigned int inet_ehashfn(struct net *net, static inline int inet_sk_ehashfn(const struct sock *sk) { const struct inet_sock *inet = inet_sk(sk); - const __be32 laddr = inet->rcv_saddr; - const __u16 lport = inet->num; - const __be32 faddr = inet->daddr; - const __be16 fport = inet->dport; + const __be32 laddr = inet->inet_rcv_saddr; + const __u16 lport = inet->inet_num; + const __be32 faddr = inet->inet_daddr; + const __be16 fport = inet->inet_dport; struct net *net = sock_net(sk); return inet_ehashfn(net, laddr, lport, faddr, fport); diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index b63b80fac56..37f3aea074a 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -194,7 +194,7 @@ static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk) static inline __be32 inet_rcv_saddr(const struct sock *sk) { return likely(sk->sk_state != TCP_TIME_WAIT) ? - inet_sk(sk)->rcv_saddr : inet_twsk(sk)->tw_rcv_saddr; + inet_sk(sk)->inet_rcv_saddr : inet_twsk(sk)->tw_rcv_saddr; } extern void inet_twsk_put(struct inet_timewait_sock *tw); diff --git a/include/net/ip.h b/include/net/ip.h index 2f47e5482b5..376adf47764 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -240,8 +240,8 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, str * does not change, they drop every other packet in * a TCP stream using header compression. */ - iph->id = (sk && inet_sk(sk)->daddr) ? - htons(inet_sk(sk)->id++) : 0; + iph->id = (sk && inet_sk(sk)->inet_daddr) ? + htons(inet_sk(sk)->inet_id++) : 0; } else __ip_select_ident(iph, dst, 0); } @@ -249,9 +249,9 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, str static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more) { if (iph->frag_off & htons(IP_DF)) { - if (sk && inet_sk(sk)->daddr) { - iph->id = htons(inet_sk(sk)->id); - inet_sk(sk)->id += 1 + more; + if (sk && inet_sk(sk)->inet_daddr) { + iph->id = htons(inet_sk(sk)->inet_id); + inet_sk(sk)->inet_id += 1 + more; } else iph->id = 0; } else @@ -317,7 +317,7 @@ static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, ch static __inline__ void inet_reset_saddr(struct sock *sk) { - inet_sk(sk)->rcv_saddr = inet_sk(sk)->saddr = 0; + inet_sk(sk)->inet_rcv_saddr = inet_sk(sk)->inet_saddr = 0; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) if (sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 7302e1498d4..00028d4b09d 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -62,10 +62,10 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) nexthop = inet->opt->faddr; } - tmp = ip_route_connect(&rt, nexthop, inet->saddr, + tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_DCCP, - inet->sport, usin->sin_port, sk, 1); + inet->inet_sport, usin->sin_port, sk, 1); if (tmp < 0) return tmp; @@ -77,12 +77,12 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (inet->opt == NULL || !inet->opt->srr) daddr = rt->rt_dst; - if (inet->saddr == 0) - inet->saddr = rt->rt_src; - inet->rcv_saddr = inet->saddr; + if (inet->inet_saddr == 0) + inet->inet_saddr = rt->rt_src; + inet->inet_rcv_saddr = inet->inet_saddr; - inet->dport = usin->sin_port; - inet->daddr = daddr; + inet->inet_dport = usin->sin_port; + inet->inet_daddr = daddr; inet_csk(sk)->icsk_ext_hdr_len = 0; if (inet->opt != NULL) @@ -98,17 +98,19 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err != 0) goto failure; - err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport, - sk); + err = ip_route_newports(&rt, IPPROTO_DCCP, inet->inet_sport, + inet->inet_dport, sk); if (err != 0) goto failure; /* OK, now commit destination to socket. */ sk_setup_caps(sk, &rt->u.dst); - dp->dccps_iss = secure_dccp_sequence_number(inet->saddr, inet->daddr, - inet->sport, inet->dport); - inet->id = dp->dccps_iss ^ jiffies; + dp->dccps_iss = secure_dccp_sequence_number(inet->inet_saddr, + inet->inet_daddr, + inet->inet_sport, + inet->inet_dport); + inet->inet_id = dp->dccps_iss ^ jiffies; err = dccp_connect(sk); rt = NULL; @@ -123,7 +125,7 @@ failure: dccp_set_state(sk, DCCP_CLOSED); ip_rt_put(rt); sk->sk_route_caps = 0; - inet->dport = 0; + inet->inet_dport = 0; goto out; } @@ -352,7 +354,9 @@ void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb) struct dccp_hdr *dh = dccp_hdr(skb); dccp_csum_outgoing(skb); - dh->dccph_checksum = dccp_v4_csum_finish(skb, inet->saddr, inet->daddr); + dh->dccph_checksum = dccp_v4_csum_finish(skb, + inet->inet_saddr, + inet->inet_daddr); } EXPORT_SYMBOL_GPL(dccp_v4_send_check); @@ -393,14 +397,14 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, newinet = inet_sk(newsk); ireq = inet_rsk(req); - newinet->daddr = ireq->rmt_addr; - newinet->rcv_saddr = ireq->loc_addr; - newinet->saddr = ireq->loc_addr; + newinet->inet_daddr = ireq->rmt_addr; + newinet->inet_rcv_saddr = ireq->loc_addr; + newinet->inet_saddr = ireq->loc_addr; newinet->opt = ireq->opt; ireq->opt = NULL; newinet->mc_index = inet_iif(skb); newinet->mc_ttl = ip_hdr(skb)->ttl; - newinet->id = jiffies; + newinet->inet_id = jiffies; dccp_sync_mss(newsk, dst_mtu(dst)); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index a2afb553d8b..6d89f9f7d5d 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -158,8 +158,8 @@ static void dccp_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.fl_ip_dport = inet->dport; - fl.fl_ip_sport = inet->sport; + fl.fl_ip_dport = inet->inet_dport; + fl.fl_ip_sport = inet->inet_sport; security_sk_classify_flow(sk, &fl); err = ip6_dst_lookup(sk, &dst, &fl); @@ -510,9 +510,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, memcpy(newnp, np, sizeof(struct ipv6_pinfo)); - ipv6_addr_set_v4mapped(newinet->daddr, &newnp->daddr); + ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr); - ipv6_addr_set_v4mapped(newinet->saddr, &newnp->saddr); + ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr); @@ -640,7 +640,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, dccp_sync_mss(newsk, dst_mtu(dst)); - newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; + newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; + newinet->inet_rcv_saddr = LOOPBACK4_IPV6; __inet6_hash(newsk); __inet_inherit_port(sk, newsk); @@ -968,10 +969,9 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, icsk->icsk_af_ops = &dccp_ipv6_af_ops; sk->sk_backlog_rcv = dccp_v6_do_rcv; goto failure; - } else { - ipv6_addr_set_v4mapped(inet->saddr, &np->saddr); - ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr); } + ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); + ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr); return err; } @@ -984,7 +984,7 @@ static int dccp_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.fl_ip_dport = usin->sin6_port; - fl.fl_ip_sport = inet->sport; + fl.fl_ip_sport = inet->inet_sport; security_sk_classify_flow(sk, &fl); if (np->opt != NULL && np->opt->srcrt != NULL) { @@ -1017,7 +1017,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, /* set the source address */ ipv6_addr_copy(&np->saddr, saddr); - inet->rcv_saddr = LOOPBACK4_IPV6; + inet->inet_rcv_saddr = LOOPBACK4_IPV6; __ip6_dst_store(sk, dst, NULL, NULL); @@ -1026,7 +1026,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, icsk->icsk_ext_hdr_len = (np->opt->opt_flen + np->opt->opt_nflen); - inet->dport = usin->sin6_port; + inet->inet_dport = usin->sin6_port; dccp_set_state(sk, DCCP_REQUESTING); err = inet6_hash_connect(&dccp_death_row, sk); @@ -1035,7 +1035,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32, np->daddr.s6_addr32, - inet->sport, inet->dport); + inet->inet_sport, + inet->inet_dport); err = dccp_connect(sk); if (err) goto late_failure; @@ -1046,7 +1047,7 @@ late_failure: dccp_set_state(sk, DCCP_CLOSED); __sk_dst_reset(sk); failure: - inet->dport = 0; + inet->inet_dport = 0; sk->sk_route_caps = 0; return err; } diff --git a/net/dccp/output.c b/net/dccp/output.c index c96119fda68..d6bb753bf6a 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -99,8 +99,8 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) /* Build DCCP header and checksum it. */ dh = dccp_zeroed_hdr(skb, dccp_header_size); dh->dccph_type = dcb->dccpd_type; - dh->dccph_sport = inet->sport; - dh->dccph_dport = inet->dport; + dh->dccph_sport = inet->inet_sport; + dh->dccph_dport = inet->inet_dport; dh->dccph_doff = (dccp_header_size + dcb->dccpd_opt_len) / 4; dh->dccph_ccval = dcb->dccpd_ccval; dh->dccph_cscov = dp->dccps_pcslen; diff --git a/net/dccp/probe.c b/net/dccp/probe.c index 5e6ec8b9b7b..dc328425fa2 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -80,19 +80,20 @@ static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk, if (ccid_get_current_tx_ccid(dccp_sk(sk)) == DCCPC_CCID3) hc = ccid3_hc_tx_sk(sk); - if (port == 0 || ntohs(inet->dport) == port || - ntohs(inet->sport) == port) { + if (port == 0 || ntohs(inet->inet_dport) == port || + ntohs(inet->inet_sport) == port) { 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, + &inet->inet_saddr, ntohs(inet->inet_sport), + &inet->inet_daddr, ntohs(inet->inet_dport), size, 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), - &inet->daddr, ntohs(inet->dport), size); + &inet->inet_saddr, ntohs(inet->inet_sport), + &inet->inet_daddr, ntohs(inet->inet_dport), + size); } jprobe_return(); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index ecb203fff50..671cd1413d5 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -278,7 +278,7 @@ int dccp_disconnect(struct sock *sk, int flags) sk->sk_send_head = NULL; } - inet->dport = 0; + inet->inet_dport = 0; if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) inet_reset_saddr(sk); @@ -290,7 +290,7 @@ int dccp_disconnect(struct sock *sk, int flags) inet_csk_delack_init(sk); __sk_dst_reset(sk); - WARN_ON(inet->num && !icsk->icsk_bind_hash); + WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); sk->sk_error_report(sk); return err; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 1deff48b122..04a14b1600a 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -174,12 +174,12 @@ static int inet_autobind(struct sock *sk) /* We may need to bind the socket. */ lock_sock(sk); inet = inet_sk(sk); - if (!inet->num) { + if (!inet->inet_num) { if (sk->sk_prot->get_port(sk, 0)) { release_sock(sk); return -EAGAIN; } - inet->sport = htons(inet->num); + inet->inet_sport = htons(inet->inet_num); } release_sock(sk); return 0; @@ -354,7 +354,7 @@ lookup_protocol: inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0; if (SOCK_RAW == sock->type) { - inet->num = protocol; + inet->inet_num = protocol; if (IPPROTO_RAW == protocol) inet->hdrincl = 1; } @@ -364,7 +364,7 @@ lookup_protocol: else inet->pmtudisc = IP_PMTUDISC_WANT; - inet->id = 0; + inet->inet_id = 0; sock_init_data(sock, sk); @@ -381,13 +381,13 @@ lookup_protocol: sk_refcnt_debug_inc(sk); - if (inet->num) { + if (inet->inet_num) { /* It assumes that any protocol which allows * the user to assign a number at socket * creation time automatically * shares. */ - inet->sport = htons(inet->num); + inet->inet_sport = htons(inet->inet_num); /* Add to protocol hash chains. */ sk->sk_prot->hash(sk); } @@ -494,27 +494,27 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) /* Check these errors (active socket, double bind). */ err = -EINVAL; - if (sk->sk_state != TCP_CLOSE || inet->num) + if (sk->sk_state != TCP_CLOSE || inet->inet_num) goto out_release_sock; - inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; + inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) - inet->saddr = 0; /* Use device */ + inet->inet_saddr = 0; /* Use device */ /* Make sure we are allowed to bind here. */ if (sk->sk_prot->get_port(sk, snum)) { - inet->saddr = inet->rcv_saddr = 0; + inet->inet_saddr = inet->inet_rcv_saddr = 0; err = -EADDRINUSE; goto out_release_sock; } - if (inet->rcv_saddr) + if (inet->inet_rcv_saddr) sk->sk_userlocks |= SOCK_BINDADDR_LOCK; if (snum) sk->sk_userlocks |= SOCK_BINDPORT_LOCK; - inet->sport = htons(inet->num); - inet->daddr = 0; - inet->dport = 0; + inet->inet_sport = htons(inet->inet_num); + inet->inet_daddr = 0; + inet->inet_dport = 0; sk_dst_reset(sk); err = 0; out_release_sock: @@ -532,7 +532,7 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, if (uaddr->sa_family == AF_UNSPEC) return sk->sk_prot->disconnect(sk, flags); - if (!inet_sk(sk)->num && inet_autobind(sk)) + if (!inet_sk(sk)->inet_num && inet_autobind(sk)) return -EAGAIN; return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len); } @@ -689,17 +689,17 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, sin->sin_family = AF_INET; if (peer) { - if (!inet->dport || + if (!inet->inet_dport || (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && peer == 1)) return -ENOTCONN; - sin->sin_port = inet->dport; - sin->sin_addr.s_addr = inet->daddr; + sin->sin_port = inet->inet_dport; + sin->sin_addr.s_addr = inet->inet_daddr; } else { - __be32 addr = inet->rcv_saddr; + __be32 addr = inet->inet_rcv_saddr; if (!addr) - addr = inet->saddr; - sin->sin_port = inet->sport; + addr = inet->inet_saddr; + sin->sin_port = inet->inet_sport; sin->sin_addr.s_addr = addr; } memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); @@ -714,7 +714,7 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, struct sock *sk = sock->sk; /* We may need to bind the socket. */ - if (!inet_sk(sk)->num && inet_autobind(sk)) + if (!inet_sk(sk)->inet_num && inet_autobind(sk)) return -EAGAIN; return sk->sk_prot->sendmsg(iocb, sk, msg, size); @@ -728,7 +728,7 @@ static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, struct sock *sk = sock->sk; /* We may need to bind the socket. */ - if (!inet_sk(sk)->num && inet_autobind(sk)) + if (!inet_sk(sk)->inet_num && inet_autobind(sk)) return -EAGAIN; if (sk->sk_prot->sendpage) @@ -1059,9 +1059,9 @@ static int inet_sk_reselect_saddr(struct sock *sk) struct inet_sock *inet = inet_sk(sk); int err; struct rtable *rt; - __be32 old_saddr = inet->saddr; + __be32 old_saddr = inet->inet_saddr; __be32 new_saddr; - __be32 daddr = inet->daddr; + __be32 daddr = inet->inet_daddr; if (inet->opt && inet->opt->srr) daddr = inet->opt->faddr; @@ -1071,7 +1071,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, sk->sk_protocol, - inet->sport, inet->dport, sk, 0); + inet->inet_sport, inet->inet_dport, sk, 0); if (err) return err; @@ -1087,7 +1087,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) __func__, &old_saddr, &new_saddr); } - inet->saddr = inet->rcv_saddr = new_saddr; + inet->inet_saddr = inet->inet_rcv_saddr = new_saddr; /* * XXX The only one ugly spot where we need to @@ -1113,7 +1113,7 @@ int inet_sk_rebuild_header(struct sock *sk) return 0; /* Reroute. */ - daddr = inet->daddr; + daddr = inet->inet_daddr; if (inet->opt && inet->opt->srr) daddr = inet->opt->faddr; { @@ -1123,7 +1123,7 @@ int inet_sk_rebuild_header(struct sock *sk) .nl_u = { .ip4_u = { .daddr = daddr, - .saddr = inet->saddr, + .saddr = inet->inet_saddr, .tos = RT_CONN_FLAGS(sk), }, }, @@ -1131,8 +1131,8 @@ int inet_sk_rebuild_header(struct sock *sk) .flags = inet_sk_flowi_flags(sk), .uli_u = { .ports = { - .sport = inet->sport, - .dport = inet->dport, + .sport = inet->inet_sport, + .dport = inet->inet_dport, }, }, }; diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 5e6c5a0f3fd..fb2465811b4 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -39,7 +39,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk_dst_reset(sk); oif = sk->sk_bound_dev_if; - saddr = inet->saddr; + saddr = inet->inet_saddr; if (ipv4_is_multicast(usin->sin_addr.s_addr)) { if (!oif) oif = inet->mc_index; @@ -49,7 +49,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, sk->sk_protocol, - inet->sport, usin->sin_port, sk, 1); + inet->inet_sport, usin->sin_port, sk, 1); if (err) { if (err == -ENETUNREACH) IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); @@ -60,14 +60,14 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ip_rt_put(rt); return -EACCES; } - if (!inet->saddr) - inet->saddr = rt->rt_src; /* Update source address */ - if (!inet->rcv_saddr) - inet->rcv_saddr = rt->rt_src; - inet->daddr = rt->rt_dst; - inet->dport = usin->sin_port; + if (!inet->inet_saddr) + inet->inet_saddr = rt->rt_src; /* Update source address */ + if (!inet->inet_rcv_saddr) + inet->inet_rcv_saddr = rt->rt_src; + inet->inet_daddr = rt->rt_dst; + inet->inet_dport = usin->sin_port; sk->sk_state = TCP_ESTABLISHED; - inet->id = jiffies; + inet->inet_id = jiffies; sk_dst_set(sk, &rt->u.dst); return(0); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 9139e8f6fdb..f6a0af75993 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -368,7 +368,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, .proto = sk->sk_protocol, .flags = inet_sk_flowi_flags(sk), .uli_u = { .ports = - { .sport = inet_sk(sk)->sport, + { .sport = inet_sk(sk)->inet_sport, .dport = ireq->rmt_port } } }; struct net *net = sock_net(sk); @@ -547,9 +547,9 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req, newsk->sk_state = TCP_SYN_RECV; newicsk->icsk_bind_hash = NULL; - inet_sk(newsk)->dport = inet_rsk(req)->rmt_port; - inet_sk(newsk)->num = ntohs(inet_rsk(req)->loc_port); - inet_sk(newsk)->sport = inet_rsk(req)->loc_port; + inet_sk(newsk)->inet_dport = inet_rsk(req)->rmt_port; + inet_sk(newsk)->inet_num = ntohs(inet_rsk(req)->loc_port); + inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port; newsk->sk_write_space = sk_stream_write_space; newicsk->icsk_retransmits = 0; @@ -580,8 +580,8 @@ void inet_csk_destroy_sock(struct sock *sk) /* It cannot be in hash table! */ WARN_ON(!sk_unhashed(sk)); - /* If it has not 0 inet_sk(sk)->num, it must be bound */ - WARN_ON(inet_sk(sk)->num && !inet_csk(sk)->icsk_bind_hash); + /* If it has not 0 inet_sk(sk)->inet_num, it must be bound */ + WARN_ON(inet_sk(sk)->inet_num && !inet_csk(sk)->icsk_bind_hash); sk->sk_prot->destroy(sk); @@ -616,8 +616,8 @@ int inet_csk_listen_start(struct sock *sk, const int nr_table_entries) * after validation is complete. */ sk->sk_state = TCP_LISTEN; - if (!sk->sk_prot->get_port(sk, inet->num)) { - inet->sport = htons(inet->num); + if (!sk->sk_prot->get_port(sk, inet->inet_num)) { + inet->inet_sport = htons(inet->inet_num); sk_dst_reset(sk); sk->sk_prot->hash(sk); @@ -693,8 +693,8 @@ void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) const struct inet_sock *inet = inet_sk(sk); sin->sin_family = AF_INET; - sin->sin_addr.s_addr = inet->daddr; - sin->sin_port = inet->dport; + sin->sin_addr.s_addr = inet->inet_daddr; + sin->sin_port = inet->inet_dport; } EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index cb73fdefba9..bdb78dd180c 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -116,10 +116,10 @@ static int inet_csk_diag_fill(struct sock *sk, r->id.idiag_cookie[0] = (u32)(unsigned long)sk; r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1); - r->id.idiag_sport = inet->sport; - r->id.idiag_dport = inet->dport; - r->id.idiag_src[0] = inet->rcv_saddr; - r->id.idiag_dst[0] = inet->daddr; + r->id.idiag_sport = inet->inet_sport; + r->id.idiag_dport = inet->inet_dport; + r->id.idiag_src[0] = inet->inet_rcv_saddr; + r->id.idiag_dst[0] = inet->inet_daddr; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) if (r->idiag_family == AF_INET6) { @@ -504,11 +504,11 @@ static int inet_csk_diag_dump(struct sock *sk, } else #endif { - entry.saddr = &inet->rcv_saddr; - entry.daddr = &inet->daddr; + entry.saddr = &inet->inet_rcv_saddr; + entry.daddr = &inet->inet_daddr; } - entry.sport = inet->num; - entry.dport = ntohs(inet->dport); + entry.sport = inet->inet_num; + entry.dport = ntohs(inet->inet_dport); entry.userlocks = sk->sk_userlocks; if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry)) @@ -584,7 +584,7 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk, if (tmo < 0) tmo = 0; - r->id.idiag_sport = inet->sport; + r->id.idiag_sport = inet->inet_sport; r->id.idiag_dport = ireq->rmt_port; r->id.idiag_src[0] = ireq->loc_addr; r->id.idiag_dst[0] = ireq->rmt_addr; @@ -639,7 +639,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) { bc = (struct rtattr *)(r + 1); - entry.sport = inet->num; + entry.sport = inet->inet_num; entry.userlocks = sk->sk_userlocks; } @@ -732,7 +732,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) continue; } - if (r->id.idiag_sport != inet->sport && + if (r->id.idiag_sport != inet->inet_sport && r->id.idiag_sport) goto next_listen; @@ -797,10 +797,10 @@ skip_listen_ht: goto next_normal; if (!(r->idiag_states & (1 << sk->sk_state))) goto next_normal; - if (r->id.idiag_sport != inet->sport && + if (r->id.idiag_sport != inet->inet_sport && r->id.idiag_sport) goto next_normal; - if (r->id.idiag_dport != inet->dport && + if (r->id.idiag_dport != inet->inet_dport && r->id.idiag_dport) goto next_normal; if (inet_csk_diag_dump(sk, skb, cb) < 0) { diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index a45aaf3d48b..47ad7aab51e 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -64,7 +64,7 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, atomic_inc(&hashinfo->bsockets); - inet_sk(sk)->num = snum; + inet_sk(sk)->inet_num = snum; sk_add_bind_node(sk, &tb->owners); tb->num_owners++; inet_csk(sk)->icsk_bind_hash = tb; @@ -76,7 +76,7 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, static void __inet_put_port(struct sock *sk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - const int bhash = inet_bhashfn(sock_net(sk), inet_sk(sk)->num, + const int bhash = inet_bhashfn(sock_net(sk), inet_sk(sk)->inet_num, hashinfo->bhash_size); struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash]; struct inet_bind_bucket *tb; @@ -88,7 +88,7 @@ static void __inet_put_port(struct sock *sk) __sk_del_bind_node(sk); tb->num_owners--; inet_csk(sk)->icsk_bind_hash = NULL; - inet_sk(sk)->num = 0; + inet_sk(sk)->inet_num = 0; inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); spin_unlock(&head->lock); } @@ -105,7 +105,7 @@ EXPORT_SYMBOL(inet_put_port); void __inet_inherit_port(struct sock *sk, struct sock *child) { struct inet_hashinfo *table = sk->sk_prot->h.hashinfo; - const int bhash = inet_bhashfn(sock_net(sk), inet_sk(child)->num, + const int bhash = inet_bhashfn(sock_net(sk), inet_sk(child)->inet_num, table->bhash_size); struct inet_bind_hashbucket *head = &table->bhash[bhash]; struct inet_bind_bucket *tb; @@ -126,9 +126,9 @@ static inline int compute_score(struct sock *sk, struct net *net, int score = -1; struct inet_sock *inet = inet_sk(sk); - if (net_eq(sock_net(sk), net) && inet->num == hnum && + if (net_eq(sock_net(sk), net) && inet->inet_num == hnum && !ipv6_only_sock(sk)) { - __be32 rcv_saddr = inet->rcv_saddr; + __be32 rcv_saddr = inet->inet_rcv_saddr; score = sk->sk_family == PF_INET ? 1 : 0; if (rcv_saddr) { if (rcv_saddr != daddr) @@ -273,13 +273,14 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, { struct inet_hashinfo *hinfo = death_row->hashinfo; struct inet_sock *inet = inet_sk(sk); - __be32 daddr = inet->rcv_saddr; - __be32 saddr = inet->daddr; + __be32 daddr = inet->inet_rcv_saddr; + __be32 saddr = inet->inet_daddr; int dif = sk->sk_bound_dev_if; INET_ADDR_COOKIE(acookie, saddr, daddr) - const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); + const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); struct net *net = sock_net(sk); - unsigned int hash = inet_ehashfn(net, daddr, lport, saddr, inet->dport); + unsigned int hash = inet_ehashfn(net, daddr, lport, + saddr, inet->inet_dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); spinlock_t *lock = inet_ehash_lockp(hinfo, hash); struct sock *sk2; @@ -312,8 +313,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, unique: /* Must record num and sport now. Otherwise we will see * in hash table socket with a funny identity. */ - inet->num = lport; - inet->sport = htons(lport); + inet->inet_num = lport; + inet->inet_sport = htons(lport); sk->sk_hash = hash; WARN_ON(!sk_unhashed(sk)); __sk_nulls_add_node_rcu(sk, &head->chain); @@ -341,8 +342,9 @@ not_unique: static inline u32 inet_sk_port_offset(const struct sock *sk) { const struct inet_sock *inet = inet_sk(sk); - return secure_ipv4_port_ephemeral(inet->rcv_saddr, inet->daddr, - inet->dport); + return secure_ipv4_port_ephemeral(inet->inet_rcv_saddr, + inet->inet_daddr, + inet->inet_dport); } void __inet_hash_nolisten(struct sock *sk) @@ -424,7 +426,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, void (*hash)(struct sock *sk)) { struct inet_hashinfo *hinfo = death_row->hashinfo; - const unsigned short snum = inet_sk(sk)->num; + const unsigned short snum = inet_sk(sk)->inet_num; struct inet_bind_hashbucket *head; struct inet_bind_bucket *tb; int ret; @@ -485,7 +487,7 @@ ok: /* Head lock still held and bh's disabled */ inet_bind_hash(sk, tb, port); if (sk_unhashed(sk)) { - inet_sk(sk)->sport = htons(port); + inet_sk(sk)->inet_sport = htons(port); hash(sk); } spin_unlock(&head->lock); diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 2fe571155b2..1f5d508bb18 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -86,7 +86,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, Note, that any socket with inet->num != 0 MUST be bound in binding cache, even if it is closed. */ - bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), inet->num, + bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), inet->inet_num, hashinfo->bhash_size)]; spin_lock(&bhead->lock); tw->tw_tb = icsk->icsk_bind_hash; @@ -124,14 +124,14 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat kmemcheck_annotate_bitfield(tw, flags); /* Give us an identity. */ - tw->tw_daddr = inet->daddr; - tw->tw_rcv_saddr = inet->rcv_saddr; + tw->tw_daddr = inet->inet_daddr; + tw->tw_rcv_saddr = inet->inet_rcv_saddr; tw->tw_bound_dev_if = sk->sk_bound_dev_if; - tw->tw_num = inet->num; + tw->tw_num = inet->inet_num; tw->tw_state = TCP_TIME_WAIT; tw->tw_substate = state; - tw->tw_sport = inet->sport; - tw->tw_dport = inet->dport; + tw->tw_sport = inet->inet_sport; + tw->tw_dport = inet->inet_dport; tw->tw_family = sk->sk_family; tw->tw_reuse = sk->sk_reuse; tw->tw_hash = sk->sk_hash; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 6c98b43badf..fdf51badc8e 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -161,7 +161,7 @@ int ip_call_ra_chain(struct sk_buff *skb) /* If socket is bound to an interface, only report * the packet if it came from that interface. */ - if (sk && inet_sk(sk)->num == protocol && + if (sk && inet_sk(sk)->inet_num == protocol && (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) && sock_net(sk) == dev_net(dev)) { diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f9895180f48..322b40864ac 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -329,7 +329,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) __be32 daddr; /* Use correct destination address if we have options. */ - daddr = inet->daddr; + daddr = inet->inet_daddr; if(opt && opt->srr) daddr = opt->faddr; @@ -338,13 +338,13 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = daddr, - .saddr = inet->saddr, + .saddr = inet->inet_saddr, .tos = RT_CONN_FLAGS(sk) } }, .proto = sk->sk_protocol, .flags = inet_sk_flowi_flags(sk), .uli_u = { .ports = - { .sport = inet->sport, - .dport = inet->dport } } }; + { .sport = inet->inet_sport, + .dport = inet->inet_dport } } }; /* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times @@ -379,7 +379,7 @@ packet_routed: if (opt && opt->optlen) { iph->ihl += opt->optlen >> 2; - ip_options_build(skb, opt, inet->daddr, rt, 0); + ip_options_build(skb, opt, inet->inet_daddr, rt, 0); } ip_select_ident_more(iph, &rt->u.dst, sk, @@ -846,7 +846,8 @@ int ip_append_data(struct sock *sk, maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; if (inet->cork.length + length > 0xFFFF - fragheaderlen) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, mtu-exthdrlen); + ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, + mtu-exthdrlen); return -EMSGSIZE; } @@ -1100,7 +1101,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; if (inet->cork.length + size > 0xFFFF - fragheaderlen) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, mtu); + ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, mtu); return -EMSGSIZE; } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 0c0b6e363a2..c602d985fe1 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -245,7 +245,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, { struct ip_ra_chain *ra, *new_ra, **rap; - if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num == IPPROTO_RAW) + if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW) return -EINVAL; new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; @@ -492,7 +492,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, if (sk->sk_family == PF_INET || (!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && - inet->daddr != LOOPBACK4_IPV6)) { + inet->inet_daddr != LOOPBACK4_IPV6)) { #endif if (inet->opt) icsk->icsk_ext_hdr_len -= inet->opt->optlen; @@ -1181,8 +1181,8 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, if (inet->cmsg_flags & IP_CMSG_PKTINFO) { struct in_pktinfo info; - info.ipi_addr.s_addr = inet->rcv_saddr; - info.ipi_spec_dst.s_addr = inet->rcv_saddr; + info.ipi_addr.s_addr = inet->inet_rcv_saddr; + info.ipi_spec_dst.s_addr = inet->inet_rcv_saddr; info.ipi_ifindex = inet->mc_index; put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index c757f0b4b74..694974502ea 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -956,7 +956,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi switch (optname) { case MRT_INIT: if (sk->sk_type != SOCK_RAW || - inet_sk(sk)->num != IPPROTO_IGMP) + inet_sk(sk)->inet_num != IPPROTO_IGMP) return -EOPNOTSUPP; if (optlen != sizeof(int)) return -ENOPROTOOPT; diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index aa95bb82ee6..9cd423ffafa 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -255,10 +255,10 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) struct nf_conntrack_tuple tuple; memset(&tuple, 0, sizeof(tuple)); - tuple.src.u3.ip = inet->rcv_saddr; - tuple.src.u.tcp.port = inet->sport; - tuple.dst.u3.ip = inet->daddr; - tuple.dst.u.tcp.port = inet->dport; + tuple.src.u3.ip = inet->inet_rcv_saddr; + tuple.src.u.tcp.port = inet->inet_sport; + tuple.dst.u3.ip = inet->inet_daddr; + tuple.dst.u.tcp.port = inet->inet_dport; tuple.src.l3num = PF_INET; tuple.dst.protonum = sk->sk_protocol; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 39e2a6b8752..9ef8c0829a7 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -87,7 +87,7 @@ void raw_hash_sk(struct sock *sk) struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; struct hlist_head *head; - head = &h->ht[inet_sk(sk)->num & (RAW_HTABLE_SIZE - 1)]; + head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)]; write_lock_bh(&h->lock); sk_add_node(sk, head); @@ -115,9 +115,9 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, sk_for_each_from(sk, node) { struct inet_sock *inet = inet_sk(sk); - if (net_eq(sock_net(sk), net) && inet->num == num && - !(inet->daddr && inet->daddr != raddr) && - !(inet->rcv_saddr && inet->rcv_saddr != laddr) && + if (net_eq(sock_net(sk), net) && inet->inet_num == num && + !(inet->inet_daddr && inet->inet_daddr != raddr) && + !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) goto found; /* gotcha */ } @@ -326,7 +326,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, int err; if (length > rt->u.dst.dev->mtu) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, + ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, rt->u.dst.dev->mtu); return -EMSGSIZE; } @@ -489,10 +489,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, err = -EDESTADDRREQ; if (sk->sk_state != TCP_ESTABLISHED) goto out; - daddr = inet->daddr; + daddr = inet->inet_daddr; } - ipc.addr = inet->saddr; + ipc.addr = inet->inet_saddr; ipc.opt = NULL; ipc.shtx.flags = 0; ipc.oif = sk->sk_bound_dev_if; @@ -634,9 +634,9 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) goto out; - inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; + inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) - inet->saddr = 0; /* Use device */ + inet->inet_saddr = 0; /* Use device */ sk_dst_reset(sk); ret = 0; out: return ret; @@ -706,7 +706,7 @@ static int raw_init(struct sock *sk) { struct raw_sock *rp = raw_sk(sk); - if (inet_sk(sk)->num == IPPROTO_ICMP) + if (inet_sk(sk)->inet_num == IPPROTO_ICMP) memset(&rp->filter, 0, sizeof(rp->filter)); return 0; } @@ -743,7 +743,7 @@ static int do_raw_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen) { if (optname == ICMP_FILTER) { - if (inet_sk(sk)->num != IPPROTO_ICMP) + if (inet_sk(sk)->inet_num != IPPROTO_ICMP) return -EOPNOTSUPP; else return raw_seticmpfilter(sk, optval, optlen); @@ -773,7 +773,7 @@ static int do_raw_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { if (optname == ICMP_FILTER) { - if (inet_sk(sk)->num != IPPROTO_ICMP) + if (inet_sk(sk)->inet_num != IPPROTO_ICMP) return -EOPNOTSUPP; else return raw_geticmpfilter(sk, optval, optlen); @@ -932,10 +932,10 @@ EXPORT_SYMBOL_GPL(raw_seq_stop); static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) { struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->daddr, - src = inet->rcv_saddr; + __be32 dest = inet->inet_daddr, + src = inet->inet_rcv_saddr; __u16 destp = 0, - srcp = inet->num; + srcp = inet->inet_num; seq_printf(seq, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index cf13726259c..206a291dff0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1998,7 +1998,7 @@ int tcp_disconnect(struct sock *sk, int flags) __skb_queue_purge(&sk->sk_async_wait_queue); #endif - inet->dport = 0; + inet->inet_dport = 0; if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) inet_reset_saddr(sk); @@ -2022,7 +2022,7 @@ int tcp_disconnect(struct sock *sk, int flags) memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); __sk_dst_reset(sk); - WARN_ON(inet->num && !icsk->icsk_bind_hash); + WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); sk->sk_error_report(sk); return err; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 99718703d04..a4a3390a528 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -165,10 +165,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) nexthop = inet->opt->faddr; } - tmp = ip_route_connect(&rt, nexthop, inet->saddr, + tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_TCP, - inet->sport, usin->sin_port, sk, 1); + inet->inet_sport, usin->sin_port, sk, 1); if (tmp < 0) { if (tmp == -ENETUNREACH) IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); @@ -183,11 +183,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!inet->opt || !inet->opt->srr) daddr = rt->rt_dst; - if (!inet->saddr) - inet->saddr = rt->rt_src; - inet->rcv_saddr = inet->saddr; + if (!inet->inet_saddr) + inet->inet_saddr = rt->rt_src; + inet->inet_rcv_saddr = inet->inet_saddr; - if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) { + if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) { /* Reset inherited state */ tp->rx_opt.ts_recent = 0; tp->rx_opt.ts_recent_stamp = 0; @@ -210,8 +210,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } } - inet->dport = usin->sin_port; - inet->daddr = daddr; + inet->inet_dport = usin->sin_port; + inet->inet_daddr = daddr; inet_csk(sk)->icsk_ext_hdr_len = 0; if (inet->opt) @@ -230,7 +230,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) goto failure; err = ip_route_newports(&rt, IPPROTO_TCP, - inet->sport, inet->dport, sk); + inet->inet_sport, inet->inet_dport, sk); if (err) goto failure; @@ -239,12 +239,12 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk_setup_caps(sk, &rt->u.dst); if (!tp->write_seq) - tp->write_seq = secure_tcp_sequence_number(inet->saddr, - inet->daddr, - inet->sport, + tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr, + inet->inet_daddr, + inet->inet_sport, usin->sin_port); - inet->id = tp->write_seq ^ jiffies; + inet->inet_id = tp->write_seq ^ jiffies; err = tcp_connect(sk); rt = NULL; @@ -261,7 +261,7 @@ failure: tcp_set_state(sk, TCP_CLOSE); ip_rt_put(rt); sk->sk_route_caps = 0; - inet->dport = 0; + inet->inet_dport = 0; return err; } @@ -520,12 +520,13 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) struct tcphdr *th = tcp_hdr(skb); if (skb->ip_summed == CHECKSUM_PARTIAL) { - th->check = ~tcp_v4_check(len, inet->saddr, - inet->daddr, 0); + th->check = ~tcp_v4_check(len, inet->inet_saddr, + inet->inet_daddr, 0); skb->csum_start = skb_transport_header(skb) - skb->head; skb->csum_offset = offsetof(struct tcphdr, check); } else { - th->check = tcp_v4_check(len, inet->saddr, inet->daddr, + th->check = tcp_v4_check(len, inet->inet_saddr, + inet->inet_daddr, csum_partial(th, th->doff << 2, skb->csum)); @@ -848,7 +849,7 @@ static struct tcp_md5sig_key * struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, struct sock *addr_sk) { - return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->daddr); + return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr); } EXPORT_SYMBOL(tcp_v4_md5_lookup); @@ -923,7 +924,7 @@ EXPORT_SYMBOL(tcp_v4_md5_do_add); static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, u8 *newkey, u8 newkeylen) { - return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->daddr, + return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->inet_daddr, newkey, newkeylen); } @@ -1089,8 +1090,8 @@ int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, __be32 saddr, daddr; if (sk) { - saddr = inet_sk(sk)->saddr; - daddr = inet_sk(sk)->daddr; + saddr = inet_sk(sk)->inet_saddr; + daddr = inet_sk(sk)->inet_daddr; } else if (req) { saddr = inet_rsk(req)->loc_addr; daddr = inet_rsk(req)->rmt_addr; @@ -1380,9 +1381,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp = tcp_sk(newsk); newinet = inet_sk(newsk); ireq = inet_rsk(req); - newinet->daddr = ireq->rmt_addr; - newinet->rcv_saddr = ireq->loc_addr; - newinet->saddr = ireq->loc_addr; + newinet->inet_daddr = ireq->rmt_addr; + newinet->inet_rcv_saddr = ireq->loc_addr; + newinet->inet_saddr = ireq->loc_addr; newinet->opt = ireq->opt; ireq->opt = NULL; newinet->mc_index = inet_iif(skb); @@ -1390,7 +1391,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, inet_csk(newsk)->icsk_ext_hdr_len = 0; if (newinet->opt) inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen; - newinet->id = newtp->write_seq ^ jiffies; + newinet->inet_id = newtp->write_seq ^ jiffies; tcp_mtup_init(newsk); tcp_sync_mss(newsk, dst_mtu(dst)); @@ -1403,7 +1404,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, #ifdef CONFIG_TCP_MD5SIG /* Copy over the MD5 key from the original socket */ - if ((key = tcp_v4_md5_do_lookup(sk, newinet->daddr)) != NULL) { + key = tcp_v4_md5_do_lookup(sk, newinet->inet_daddr); + if (key != NULL) { /* * We're using one, so create a matching key * on the newsk structure. If we fail to get @@ -1412,7 +1414,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, */ char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); if (newkey != NULL) - tcp_v4_md5_do_add(newsk, newinet->daddr, + tcp_v4_md5_do_add(newsk, newinet->inet_daddr, newkey, key->keylen); newsk->sk_route_caps &= ~NETIF_F_GSO_MASK; } @@ -1711,8 +1713,8 @@ int tcp_v4_remember_stamp(struct sock *sk) struct inet_peer *peer = NULL; int release_it = 0; - if (!rt || rt->rt_dst != inet->daddr) { - peer = inet_getpeer(inet->daddr, 1); + if (!rt || rt->rt_dst != inet->inet_daddr) { + peer = inet_getpeer(inet->inet_daddr, 1); release_it = 1; } else { if (!rt->peer) @@ -2225,7 +2227,7 @@ static void get_openreq4(struct sock *sk, struct request_sock *req, " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n", i, ireq->loc_addr, - ntohs(inet_sk(sk)->sport), + ntohs(inet_sk(sk)->inet_sport), ireq->rmt_addr, ntohs(ireq->rmt_port), TCP_SYN_RECV, @@ -2248,10 +2250,10 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) struct tcp_sock *tp = tcp_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); struct inet_sock *inet = inet_sk(sk); - __be32 dest = inet->daddr; - __be32 src = inet->rcv_saddr; - __u16 destp = ntohs(inet->dport); - __u16 srcp = ntohs(inet->sport); + __be32 dest = inet->inet_daddr; + __be32 src = inet->inet_rcv_saddr; + __u16 destp = ntohs(inet->inet_dport); + __u16 srcp = ntohs(inet->inet_sport); if (icsk->icsk_pending == ICSK_TIME_RETRANS) { timer_active = 1; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index fcd278a7080..2e2eb74ac4c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -661,8 +661,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, /* Build TCP header and checksum it. */ th = tcp_hdr(skb); - th->source = inet->sport; - th->dest = inet->dport; + th->source = inet->inet_sport; + th->dest = inet->inet_dport; th->seq = htonl(tcb->seq); th->ack_seq = htonl(tp->rcv_nxt); *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 59f5b5e7c56..7a3cc2ffad8 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -94,7 +94,8 @@ static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb, const struct inet_sock *inet = inet_sk(sk); /* Only update if port matches */ - if ((port == 0 || ntohs(inet->dport) == port || ntohs(inet->sport) == port) + if ((port == 0 || ntohs(inet->inet_dport) == port || + ntohs(inet->inet_sport) == port) && (full || tp->snd_cwnd != tcp_probe.lastcwnd)) { spin_lock(&tcp_probe.lock); @@ -103,10 +104,10 @@ static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb, struct tcp_log *p = tcp_probe.log + tcp_probe.head; p->tstamp = ktime_get(); - p->saddr = inet->saddr; - p->sport = inet->sport; - p->daddr = inet->daddr; - p->dport = inet->dport; + p->saddr = inet->inet_saddr; + p->sport = inet->inet_sport; + p->daddr = inet->inet_daddr; + p->dport = inet->inet_dport; p->length = skb->len; p->snd_nxt = tp->snd_nxt; p->snd_una = tp->snd_una; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index cdb2ca7684d..6e8996cb79d 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -303,15 +303,15 @@ void tcp_retransmit_timer(struct sock *sk) struct inet_sock *inet = inet_sk(sk); if (sk->sk_family == AF_INET) { LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", - &inet->daddr, ntohs(inet->dport), - inet->num, tp->snd_una, tp->snd_nxt); + &inet->inet_daddr, ntohs(inet->inet_dport), + inet->inet_num, tp->snd_una, tp->snd_nxt); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (sk->sk_family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", - &np->daddr, ntohs(inet->dport), - inet->num, tp->snd_una, tp->snd_nxt); + &np->daddr, ntohs(inet->inet_dport), + inet->inet_num, tp->snd_una, tp->snd_nxt); } #endif #endif diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 45a8a7e374d..ec5c7a720c0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -214,7 +214,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, goto fail_unlock; } found: - inet_sk(sk)->num = snum; + inet_sk(sk)->inet_num = snum; sk->sk_hash = snum; if (sk_unhashed(sk)) { sk_nulls_add_node_rcu(sk, &hslot->head); @@ -233,8 +233,8 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); return (!ipv6_only_sock(sk2) && - (!inet1->rcv_saddr || !inet2->rcv_saddr || - inet1->rcv_saddr == inet2->rcv_saddr)); + (!inet1->inet_rcv_saddr || !inet2->inet_rcv_saddr || + inet1->inet_rcv_saddr == inet2->inet_rcv_saddr)); } int udp_v4_get_port(struct sock *sk, unsigned short snum) @@ -253,18 +253,18 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, struct inet_sock *inet = inet_sk(sk); score = (sk->sk_family == PF_INET ? 1 : 0); - if (inet->rcv_saddr) { - if (inet->rcv_saddr != daddr) + if (inet->inet_rcv_saddr) { + if (inet->inet_rcv_saddr != daddr) return -1; score += 2; } - if (inet->daddr) { - if (inet->daddr != saddr) + if (inet->inet_daddr) { + if (inet->inet_daddr != saddr) return -1; score += 2; } - if (inet->dport) { - if (inet->dport != sport) + if (inet->inet_dport) { + if (inet->inet_dport != sport) return -1; score += 2; } @@ -360,9 +360,10 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, if (!net_eq(sock_net(s), net) || s->sk_hash != hnum || - (inet->daddr && inet->daddr != rmt_addr) || - (inet->dport != rmt_port && inet->dport) || - (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || + (inet->inet_daddr && inet->inet_daddr != rmt_addr) || + (inet->inet_dport != rmt_port && inet->inet_dport) || + (inet->inet_rcv_saddr && + inet->inet_rcv_saddr != loc_addr) || ipv6_only_sock(s) || (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) continue; @@ -646,14 +647,14 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } else { if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; - daddr = inet->daddr; - dport = inet->dport; + daddr = inet->inet_daddr; + dport = inet->inet_dport; /* Open fast path for connected socket. Route will not be used, if at least one option is set. */ connected = 1; } - ipc.addr = inet->saddr; + ipc.addr = inet->inet_saddr; ipc.oif = sk->sk_bound_dev_if; err = sock_tx_timestamp(msg, sk, &ipc.shtx); @@ -708,7 +709,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, .proto = sk->sk_protocol, .flags = inet_sk_flowi_flags(sk), .uli_u = { .ports = - { .sport = inet->sport, + { .sport = inet->inet_sport, .dport = dport } } }; struct net *net = sock_net(sk); @@ -752,7 +753,7 @@ back_from_confirm: inet->cork.fl.fl4_dst = daddr; inet->cork.fl.fl_ip_dport = dport; inet->cork.fl.fl4_src = saddr; - inet->cork.fl.fl_ip_sport = inet->sport; + inet->cork.fl.fl_ip_sport = inet->inet_sport; up->pending = AF_INET; do_append_data: @@ -1029,15 +1030,15 @@ int udp_disconnect(struct sock *sk, int flags) */ sk->sk_state = TCP_CLOSE; - inet->daddr = 0; - inet->dport = 0; + inet->inet_daddr = 0; + inet->inet_dport = 0; sk->sk_bound_dev_if = 0; if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) inet_reset_saddr(sk); if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) { sk->sk_prot->unhash(sk); - inet->sport = 0; + inet->inet_sport = 0; } sk_dst_reset(sk); return 0; @@ -1053,7 +1054,7 @@ void udp_lib_unhash(struct sock *sk) spin_lock_bh(&hslot->lock); if (sk_nulls_del_node_init_rcu(sk)) { - inet_sk(sk)->num = 0; + inet_sk(sk)->inet_num = 0; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); } spin_unlock_bh(&hslot->lock); @@ -1752,10 +1753,10 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f, int bucket, int *len) { struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->daddr; - __be32 src = inet->rcv_saddr; - __u16 destp = ntohs(inet->dport); - __u16 srcp = ntohs(inet->sport); + __be32 dest = inet->inet_daddr; + __be32 src = inet->inet_rcv_saddr; + __u16 destp = ntohs(inet->inet_dport); + __u16 srcp = ntohs(inet->inet_sport); seq_printf(f, "%5d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n", diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 94216519873..b6d05881867 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -185,7 +185,7 @@ lookup_protocol: inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0; if (SOCK_RAW == sock->type) { - inet->num = protocol; + inet->inet_num = protocol; if (IPPROTO_RAW == protocol) inet->hdrincl = 1; } @@ -228,12 +228,12 @@ lookup_protocol: */ sk_refcnt_debug_inc(sk); - if (inet->num) { + if (inet->inet_num) { /* It assumes that any protocol which allows * the user to assign a number at socket * creation time automatically shares. */ - inet->sport = htons(inet->num); + inet->inet_sport = htons(inet->inet_num); sk->sk_prot->hash(sk); } if (sk->sk_prot->init) { @@ -281,7 +281,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) lock_sock(sk); /* Check these errors (active socket, double bind). */ - if (sk->sk_state != TCP_CLOSE || inet->num) { + if (sk->sk_state != TCP_CLOSE || inet->inet_num) { err = -EINVAL; goto out; } @@ -353,8 +353,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } } - inet->rcv_saddr = v4addr; - inet->saddr = v4addr; + inet->inet_rcv_saddr = v4addr; + inet->inet_saddr = v4addr; ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); @@ -375,9 +375,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } if (snum) sk->sk_userlocks |= SOCK_BINDPORT_LOCK; - inet->sport = htons(inet->num); - inet->dport = 0; - inet->daddr = 0; + inet->inet_sport = htons(inet->inet_num); + inet->inet_dport = 0; + inet->inet_daddr = 0; out: release_sock(sk); return err; @@ -441,12 +441,12 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, sin->sin6_flowinfo = 0; sin->sin6_scope_id = 0; if (peer) { - if (!inet->dport) + if (!inet->inet_dport) return -ENOTCONN; if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && peer == 1) return -ENOTCONN; - sin->sin6_port = inet->dport; + sin->sin6_port = inet->inet_dport; ipv6_addr_copy(&sin->sin6_addr, &np->daddr); if (np->sndflow) sin->sin6_flowinfo = np->flow_label; @@ -456,7 +456,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, else ipv6_addr_copy(&sin->sin6_addr, &np->rcv_saddr); - sin->sin6_port = inet->sport; + sin->sin6_port = inet->inet_sport; } if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin->sin6_scope_id = sk->sk_bound_dev_if; @@ -655,8 +655,8 @@ int inet6_sk_rebuild_header(struct sock *sk) 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; + fl.fl_ip_dport = inet->inet_dport; + fl.fl_ip_sport = inet->inet_sport; security_sk_classify_flow(sk, &fl); if (np->opt && np->opt->srcrt) { diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index dbfec7147aa..9f70452a69e 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -98,13 +98,14 @@ ipv4_connected: if (err) goto out; - ipv6_addr_set_v4mapped(inet->daddr, &np->daddr); + ipv6_addr_set_v4mapped(inet->inet_daddr, &np->daddr); if (ipv6_addr_any(&np->saddr)) - ipv6_addr_set_v4mapped(inet->saddr, &np->saddr); + ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); if (ipv6_addr_any(&np->rcv_saddr)) - ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr); + ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, + &np->rcv_saddr); goto out; } @@ -133,7 +134,7 @@ ipv4_connected: ipv6_addr_copy(&np->daddr, daddr); np->flow_label = fl.fl6_flowlabel; - inet->dport = usin->sin6_port; + inet->inet_dport = usin->sin6_port; /* * Check for a route to destination an obtain the @@ -145,8 +146,8 @@ ipv4_connected: 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; + fl.fl_ip_dport = inet->inet_dport; + fl.fl_ip_sport = inet->inet_sport; if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) fl.oif = np->mcast_oif; @@ -188,7 +189,7 @@ ipv4_connected: if (ipv6_addr_any(&np->rcv_saddr)) { ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); - inet->rcv_saddr = LOOPBACK4_IPV6; + inet->inet_rcv_saddr = LOOPBACK4_IPV6; } ip6_dst_store(sk, dst, diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index a9f4a21b31e..19dceef4fcc 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -132,7 +132,7 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) sin6->sin6_family = AF_INET6; ipv6_addr_copy(&sin6->sin6_addr, &np->daddr); - sin6->sin6_port = inet_sk(sk)->dport; + sin6->sin6_port = inet_sk(sk)->inet_dport; /* We do not store received flowlabel for TCP */ sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = 0; @@ -195,8 +195,8 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) 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; + fl.fl_ip_sport = inet->inet_sport; + fl.fl_ip_dport = inet->inet_dport; security_sk_classify_flow(sk, &fl); if (np->opt && np->opt->srcrt) { diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 874aed86e1a..00c6a3e6cdd 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -125,7 +125,7 @@ static int inline compute_score(struct sock *sk, struct net *net, { int score = -1; - if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && + if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum && sk->sk_family == PF_INET6) { const struct ipv6_pinfo *np = inet6_sk(sk); @@ -214,10 +214,10 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, const struct in6_addr *daddr = &np->rcv_saddr; const struct in6_addr *saddr = &np->daddr; const int dif = sk->sk_bound_dev_if; - const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); + const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); struct net *net = sock_net(sk); const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, - inet->dport); + inet->inet_dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); spinlock_t *lock = inet_ehash_lockp(hinfo, hash); struct sock *sk2; @@ -248,8 +248,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, unique: /* Must record num and sport now. Otherwise we will see * in hash table socket with a funny identity. */ - inet->num = lport; - inet->sport = htons(lport); + inet->inet_num = lport; + inet->inet_sport = htons(lport); WARN_ON(!sk_unhashed(sk)); __sk_nulls_add_node_rcu(sk, &head->chain); sk->sk_hash = hash; @@ -279,7 +279,7 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk) const struct ipv6_pinfo *np = inet6_sk(sk); return secure_ipv6_port_ephemeral(np->rcv_saddr.s6_addr32, np->daddr.s6_addr32, - inet->dport); + inet->inet_dport); } int inet6_hash_connect(struct inet_timewait_death_row *death_row, diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 716153941fc..85849b4f5a3 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1297,7 +1297,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns switch (optname) { case MRT6_INIT: if (sk->sk_type != SOCK_RAW || - inet_sk(sk)->num != IPPROTO_ICMPV6) + inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; if (optlen < sizeof(int)) return -EINVAL; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index dc0f7366073..39e10ac8801 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -64,7 +64,7 @@ int ip6_ra_control(struct sock *sk, int sel) struct ip6_ra_chain *ra, *new_ra, **rap; /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ - if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) + if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW) return -ENOPROTOOPT; new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; @@ -106,7 +106,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, if (inet_sk(sk)->is_icsk) { if (opt && !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && - inet_sk(sk)->daddr != LOOPBACK4_IPV6) { + inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) { struct inet_connection_sock *icsk = inet_csk(sk); icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); @@ -234,7 +234,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, case IPV6_V6ONLY: if (optlen < sizeof(int) || - inet_sk(sk)->num) + inet_sk(sk)->inet_num) goto e_inval; np->ipv6only = valbool; retv = 0; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index fd737efed96..52ed7d7f9da 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -72,7 +72,7 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, int is_multicast = ipv6_addr_is_multicast(loc_addr); sk_for_each_from(sk, node) - if (inet_sk(sk)->num == num) { + if (inet_sk(sk)->inet_num == num) { struct ipv6_pinfo *np = inet6_sk(sk); if (!net_eq(sock_net(sk), net)) @@ -298,7 +298,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) dev_put(dev); } - inet->rcv_saddr = inet->saddr = v4addr; + inet->inet_rcv_saddr = inet->inet_saddr = v4addr; ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); if (!(addr_type & IPV6_ADDR_MULTICAST)) ipv6_addr_copy(&np->saddr, &addr->sin6_addr); @@ -415,14 +415,14 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) skb_network_header_len(skb)); if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - skb->len, inet->num, skb->csum)) + skb->len, inet->inet_num, skb->csum)) skb->ip_summed = CHECKSUM_UNNECESSARY; } if (!skb_csum_unnecessary(skb)) skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->len, - inet->num, 0)); + inet->inet_num, 0)); if (inet->hdrincl) { if (skb_checksum_complete(skb)) { @@ -765,8 +765,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, proto = ntohs(sin6->sin6_port); if (!proto) - proto = inet->num; - else if (proto != inet->num) + proto = inet->inet_num; + else if (proto != inet->inet_num) return(-EINVAL); if (proto > 255) @@ -799,7 +799,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; - proto = inet->num; + proto = inet->inet_num; daddr = &np->daddr; fl.fl6_flowlabel = np->flow_label; } @@ -966,7 +966,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_CHECKSUM: - if (inet_sk(sk)->num == IPPROTO_ICMPV6 && + if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 && level == IPPROTO_IPV6) { /* * RFC3542 tells that IPV6_CHECKSUM socket @@ -1006,7 +1006,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, break; case SOL_ICMPV6: - if (inet_sk(sk)->num != IPPROTO_ICMPV6) + if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; return rawv6_seticmpfilter(sk, level, optname, optval, optlen); @@ -1029,7 +1029,7 @@ static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, case SOL_RAW: break; case SOL_ICMPV6: - if (inet_sk(sk)->num != IPPROTO_ICMPV6) + if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; return rawv6_seticmpfilter(sk, level, optname, optval, optlen); case SOL_IPV6: @@ -1086,7 +1086,7 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, break; case SOL_ICMPV6: - if (inet_sk(sk)->num != IPPROTO_ICMPV6) + if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; return rawv6_geticmpfilter(sk, level, optname, optval, optlen); @@ -1109,7 +1109,7 @@ static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, case SOL_RAW: break; case SOL_ICMPV6: - if (inet_sk(sk)->num != IPPROTO_ICMPV6) + if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; return rawv6_geticmpfilter(sk, level, optname, optval, optlen); case SOL_IPV6: @@ -1156,7 +1156,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) static void rawv6_close(struct sock *sk, long timeout) { - if (inet_sk(sk)->num == IPPROTO_RAW) + if (inet_sk(sk)->inet_num == IPPROTO_RAW) ip6_ra_control(sk, -1); ip6mr_sk_done(sk); sk_common_release(sk); @@ -1175,7 +1175,7 @@ static int rawv6_init_sk(struct sock *sk) { struct raw6_sock *rp = raw6_sk(sk); - switch (inet_sk(sk)->num) { + switch (inet_sk(sk)->inet_num) { case IPPROTO_ICMPV6: rp->checksum = 1; rp->offset = 2; @@ -1225,7 +1225,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) dest = &np->daddr; src = &np->rcv_saddr; destp = 0; - srcp = inet_sk(sp)->num; + srcp = inet_sk(sp)->inet_num; seq_printf(seq, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index cbe55e5d9f9..c46da533888 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -254,7 +254,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) 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; + fl.fl_ip_sport = inet_sk(sk)->inet_sport; security_req_classify_flow(req, &fl); if (ip6_dst_lookup(sk, &dst, &fl)) goto out_free; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 45176305914..c54ec3615de 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -226,8 +226,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, #endif goto failure; } else { - ipv6_addr_set_v4mapped(inet->saddr, &np->saddr); - ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr); + ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); + ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, + &np->rcv_saddr); } return err; @@ -243,7 +244,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 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; + fl.fl_ip_sport = inet->inet_sport; if (np->opt && np->opt->srcrt) { struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; @@ -275,7 +276,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, /* set the source address */ ipv6_addr_copy(&np->saddr, saddr); - inet->rcv_saddr = LOOPBACK4_IPV6; + inet->inet_rcv_saddr = LOOPBACK4_IPV6; sk->sk_gso_type = SKB_GSO_TCPV6; __ip6_dst_store(sk, dst, NULL, NULL); @@ -287,7 +288,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); - inet->dport = usin->sin6_port; + inet->inet_dport = usin->sin6_port; tcp_set_state(sk, TCP_SYN_SENT); err = inet6_hash_connect(&tcp_death_row, sk); @@ -297,8 +298,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (!tp->write_seq) tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, np->daddr.s6_addr32, - inet->sport, - inet->dport); + inet->inet_sport, + inet->inet_dport); err = tcp_connect(sk); if (err) @@ -310,7 +311,7 @@ late_failure: tcp_set_state(sk, TCP_CLOSE); __sk_dst_reset(sk); failure: - inet->dport = 0; + inet->inet_dport = 0; sk->sk_route_caps = 0; return err; } @@ -383,8 +384,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 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; + fl.fl_ip_dport = inet->inet_dport; + fl.fl_ip_sport = inet->inet_sport; security_skb_classify_flow(skb, &fl); if ((err = ip6_dst_lookup(sk, &dst, &fl))) { @@ -1291,9 +1292,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_v4mapped(newinet->daddr, &newnp->daddr); + ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr); - ipv6_addr_set_v4mapped(newinet->saddr, &newnp->saddr); + ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr); @@ -1431,7 +1432,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->advmss = dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(newsk); - newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; + newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; + newinet->inet_rcv_saddr = LOOPBACK4_IPV6; #ifdef CONFIG_TCP_MD5SIG /* Copy over the MD5 key from the original socket */ @@ -1931,8 +1933,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) dest = &np->daddr; src = &np->rcv_saddr; - destp = ntohs(inet->dport); - srcp = ntohs(inet->sport); + destp = ntohs(inet->inet_dport); + srcp = ntohs(inet->inet_sport); if (icsk->icsk_pending == ICSK_TIME_RETRANS) { timer_active = 1; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b86425b7ea2..829d300a6f3 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -53,7 +53,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) { const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); - __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; + __be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr; __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); int sk_ipv6only = ipv6_only_sock(sk); int sk2_ipv6only = inet_v6_ipv6only(sk2); @@ -63,8 +63,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) /* if both are mapped, treat as IPv4 */ if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) return (!sk2_ipv6only && - (!sk_rcv_saddr || !sk2_rcv_saddr || - sk_rcv_saddr == sk2_rcv_saddr)); + (!sk1_rcv_saddr || !sk2_rcv_saddr || + sk1_rcv_saddr == sk2_rcv_saddr)); if (addr_type2 == IPV6_ADDR_ANY && !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) @@ -100,8 +100,8 @@ static inline int compute_score(struct sock *sk, struct net *net, struct inet_sock *inet = inet_sk(sk); score = 0; - if (inet->dport) { - if (inet->dport != sport) + if (inet->inet_dport) { + if (inet->inet_dport != sport) return -1; score++; } @@ -417,8 +417,8 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, if (s->sk_hash == num && s->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(s); - if (inet->dport) { - if (inet->dport != rmt_port) + if (inet->inet_dport) { + if (inet->inet_dport != rmt_port) continue; } if (!ipv6_addr_any(&np->daddr) && @@ -792,7 +792,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (ipv6_addr_v4mapped(daddr)) { struct sockaddr_in sin; sin.sin_family = AF_INET; - sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; + sin.sin_port = sin6 ? sin6->sin6_port : inet->inet_dport; sin.sin_addr.s_addr = daddr->s6_addr32[3]; msg->msg_name = &sin; msg->msg_namelen = sizeof(sin); @@ -865,7 +865,7 @@ do_udp_sendmsg: if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; - fl.fl_ip_dport = inet->dport; + fl.fl_ip_dport = inet->inet_dport; daddr = &np->daddr; fl.fl6_flowlabel = np->flow_label; connected = 1; @@ -911,7 +911,7 @@ do_udp_sendmsg: fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) ipv6_addr_copy(&fl.fl6_src, &np->saddr); - fl.fl_ip_sport = inet->sport; + fl.fl_ip_sport = inet->inet_sport; /* merge ip6_build_xmit from ip6_output */ if (opt && opt->srcrt) { @@ -1192,8 +1192,8 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket dest = &np->daddr; src = &np->rcv_saddr; - destp = ntohs(inet->dport); - srcp = ntohs(inet->sport); + destp = ntohs(inet->inet_dport); + srcp = ntohs(inet->inet_sport); seq_printf(seq, "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index ebf00ad5b19..362afbd60a9 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -149,7 +149,7 @@ socket_match(const struct sk_buff *skb, const struct xt_match_param *par, /* Ignore sockets listening on INADDR_ANY */ wildcard = (sk->sk_state != TCP_TIME_WAIT && - inet_sk(sk)->rcv_saddr == 0); + inet_sk(sk)->inet_rcv_saddr == 0); /* Ignore non-transparent sockets, if XT_SOCKET_TRANSPARENT is used */ diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c index 24b743eb0b1..45474a43686 100644 --- a/net/rds/tcp_listen.c +++ b/net/rds/tcp_listen.c @@ -67,11 +67,11 @@ static int rds_tcp_accept_one(struct socket *sock) inet = inet_sk(new_sock->sk); rdsdebug("accepted tcp %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", - NIPQUAD(inet->saddr), ntohs(inet->sport), - NIPQUAD(inet->daddr), ntohs(inet->dport)); + NIPQUAD(inet->inet_saddr), ntohs(inet->inet_sport), + NIPQUAD(inet->inet_daddr), ntohs(inet->inet_dport)); - conn = rds_conn_create(inet->saddr, inet->daddr, &rds_tcp_transport, - GFP_KERNEL); + conn = rds_conn_create(inet->inet_saddr, inet->inet_daddr, + &rds_tcp_transport, GFP_KERNEL); if (IS_ERR(conn)) { ret = PTR_ERR(conn); goto out; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 612dc878e05..d9f4cc2c786 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -296,19 +296,19 @@ static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk) { addr->v4.sin_family = AF_INET; addr->v4.sin_port = 0; - addr->v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr; + addr->v4.sin_addr.s_addr = inet_sk(sk)->inet_rcv_saddr; } /* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { - inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr; + inet_sk(sk)->inet_rcv_saddr = addr->v4.sin_addr.s_addr; } /* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { - inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr; + inet_sk(sk)->inet_daddr = addr->v4.sin_addr.s_addr; } /* Initialize a sctp_addr from an address parameter. */ @@ -598,7 +598,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, newinet = inet_sk(newsk); - newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; + newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; sk_refcnt_debug_inc(newsk); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0970e92c6ac..4085db99033 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -394,7 +394,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) /* Refresh ephemeral port. */ if (!bp->port) - bp->port = inet_sk(sk)->num; + bp->port = inet_sk(sk)->inet_num; /* Add the address to the bind address list. * Use GFP_ATOMIC since BHs will be disabled. @@ -403,7 +403,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) /* Copy back into socket for getsockname() use. */ if (!ret) { - inet_sk(sk)->sport = htons(inet_sk(sk)->num); + inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); af->to_sk_saddr(addr, sk); } @@ -1115,7 +1115,7 @@ static int __sctp_connect(struct sock* sk, } /* Initialize sk's dport and daddr for getpeername() */ - inet_sk(sk)->dport = htons(asoc->peer.port); + inet_sk(sk)->inet_dport = htons(asoc->peer.port); af = sctp_get_af_specific(sa_addr->sa.sa_family); af->to_sk_daddr(sa_addr, sk); sk->sk_err = 0; @@ -5851,7 +5851,7 @@ pp_not_found: */ success: if (!sctp_sk(sk)->bind_hash) { - inet_sk(sk)->num = snum; + inet_sk(sk)->inet_num = snum; sk_add_bind_node(sk, &pp->owner); sctp_sk(sk)->bind_hash = pp; } @@ -5923,7 +5923,7 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog) if (sctp_autobind(sk)) return -EAGAIN; } else { - if (sctp_get_port(sk, inet_sk(sk)->num)) { + if (sctp_get_port(sk, inet_sk(sk)->inet_num)) { sk->sk_state = SCTP_SS_CLOSED; return -EADDRINUSE; } @@ -6094,14 +6094,14 @@ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) static inline void __sctp_put_port(struct sock *sk) { struct sctp_bind_hashbucket *head = - &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->num)]; + &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->inet_num)]; struct sctp_bind_bucket *pp; sctp_spin_lock(&head->lock); pp = sctp_sk(sk)->bind_hash; __sk_del_bind_node(sk); sctp_sk(sk)->bind_hash = NULL; - inet_sk(sk)->num = 0; + inet_sk(sk)->inet_num = 0; sctp_bucket_destroy(pp); sctp_spin_unlock(&head->lock); } @@ -6128,7 +6128,7 @@ static int sctp_autobind(struct sock *sk) /* Initialize a local sockaddr structure to INADDR_ANY. */ af = sctp_sk(sk)->pf->af; - port = htons(inet_sk(sk)->num); + port = htons(inet_sk(sk)->inet_num); af->inaddr_any(&autoaddr, port); return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); @@ -6697,12 +6697,12 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, /* Initialize sk's sport, dport, rcv_saddr and daddr for * getsockname() and getpeername() */ - newinet->sport = inet->sport; - newinet->saddr = inet->saddr; - newinet->rcv_saddr = inet->rcv_saddr; - newinet->dport = htons(asoc->peer.port); + newinet->inet_sport = inet->inet_sport; + newinet->inet_saddr = inet->inet_saddr; + newinet->inet_rcv_saddr = inet->inet_rcv_saddr; + newinet->inet_dport = htons(asoc->peer.port); newinet->pmtudisc = inet->pmtudisc; - newinet->id = asoc->next_tsn ^ jiffies; + newinet->inet_id = asoc->next_tsn ^ jiffies; newinet->uc_ttl = inet->uc_ttl; newinet->mc_loop = 1; @@ -6741,13 +6741,13 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, newsp->hmac = NULL; /* Hook this new socket in to the bind_hash list. */ - head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->num)]; + head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->inet_num)]; sctp_local_bh_disable(); sctp_spin_lock(&head->lock); pp = sctp_sk(oldsk)->bind_hash; sk_add_bind_node(newsk, &pp->owner); sctp_sk(newsk)->bind_hash = pp; - inet_sk(newsk)->num = inet_sk(oldsk)->num; + inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; sctp_spin_unlock(&head->lock); sctp_local_bh_enable(); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index ccc5e83cae5..c2a17876def 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -272,14 +272,14 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) case PF_INET: len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n", proto_name, - &inet_sk(sk)->rcv_saddr, - inet_sk(sk)->num); + &inet_sk(sk)->inet_rcv_saddr, + inet_sk(sk)->inet_num); break; case PF_INET6: len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n", proto_name, &inet6_sk(sk)->rcv_saddr, - inet_sk(sk)->num); + inet_sk(sk)->inet_num); break; default: len = snprintf(buf, remaining, "*unknown-%d*\n", @@ -1311,7 +1311,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, /* Register socket with portmapper */ if (*errp >= 0 && pmap_register) *errp = svc_register(serv, inet->sk_family, inet->sk_protocol, - ntohs(inet_sk(inet)->sport)); + ntohs(inet_sk(inet)->inet_sport)); if (*errp < 0) { kfree(svsk); diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 3bb90b6f1dd..e04566a2c4e 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -273,11 +273,11 @@ static void dump_common_audit_data(struct audit_buffer *ab, case AF_INET: { struct inet_sock *inet = inet_sk(sk); - print_ipv4_addr(ab, inet->rcv_saddr, - inet->sport, + print_ipv4_addr(ab, inet->inet_rcv_saddr, + inet->inet_sport, "laddr", "lport"); - print_ipv4_addr(ab, inet->daddr, - inet->dport, + print_ipv4_addr(ab, inet->inet_daddr, + inet->inet_dport, "faddr", "fport"); break; } @@ -286,10 +286,10 @@ static void dump_common_audit_data(struct audit_buffer *ab, struct ipv6_pinfo *inet6 = inet6_sk(sk); print_ipv6_addr(ab, &inet6->rcv_saddr, - inet->sport, + inet->inet_sport, "laddr", "lport"); print_ipv6_addr(ab, &inet6->daddr, - inet->dport, + inet->inet_dport, "faddr", "fport"); break; } -- cgit v1.2.3 From 8edf19c2fe028563fc6ea9cb1995b8ee4172d4b6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 15 Oct 2009 00:12:40 +0000 Subject: net: sk_drops consolidation part 2 - skb_kill_datagram() can increment sk->sk_drops itself, not callers. - UDP on IPV4 & IPV6 dropped frames (because of bad checksum or policy checks) increment sk_drops Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/datagram.c | 1 + net/ipv4/udp.c | 2 ++ net/ipv6/raw.c | 1 - net/ipv6/udp.c | 4 +++- 4 files changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/datagram.c b/net/core/datagram.c index 1c6cf3a1a4f..4d57f5e12b0 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -262,6 +262,7 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) } kfree_skb(skb); + atomic_inc(&sk->sk_drops); sk_mem_reclaim_partial(sk); return err; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ec5c7a720c0..4274c1cc78f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -867,6 +867,7 @@ static unsigned int first_packet_length(struct sock *sk) udp_lib_checksum_complete(skb)) { UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, IS_UDPLITE(sk)); + atomic_inc(&sk->sk_drops); __skb_unlink(skb, rcvq); __skb_queue_tail(&list_kill, skb); } @@ -1186,6 +1187,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) drop: UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); + atomic_inc(&sk->sk_drops); kfree_skb(skb); return -1; } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 52ed7d7f9da..cb834ab7f07 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -517,7 +517,6 @@ csum_copy_err: as some normal condition. */ err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; - atomic_inc(&sk->sk_drops); goto out; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 829d300a6f3..d3b59d73f50 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -390,11 +390,13 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) if (rc == -ENOMEM) UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; + goto drop_no_sk_drops_inc; } return 0; drop: + atomic_inc(&sk->sk_drops); +drop_no_sk_drops_inc: UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); kfree_skb(skb); return -1; -- cgit v1.2.3 From dff3bb0626279bae04ed10ed61ab726d6b3ef4b4 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 7 Oct 2009 22:48:17 +0000 Subject: ah4: convert to ahash This patch converts ah4 to the new ahash interface. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 295 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 236 insertions(+), 59 deletions(-) (limited to 'net') diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 5c662703eb1..d07b0c1dd35 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,10 +6,67 @@ #include #include #include -#include +#include #include #include +struct ah_skb_cb { + struct xfrm_skb_cb xfrm; + void *tmp; +}; + +#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0])) + +static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags, + unsigned int size) +{ + unsigned int len; + + len = size + crypto_ahash_digestsize(ahash) + + (crypto_ahash_alignmask(ahash) & + ~(crypto_tfm_ctx_alignment() - 1)); + + len = ALIGN(len, crypto_tfm_ctx_alignment()); + + len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash); + len = ALIGN(len, __alignof__(struct scatterlist)); + + len += sizeof(struct scatterlist) * nfrags; + + return kmalloc(len, GFP_ATOMIC); +} + +static inline u8 *ah_tmp_auth(void *tmp, unsigned int offset) +{ + return tmp + offset; +} + +static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, + unsigned int offset) +{ + return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); +} + +static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, + u8 *icv) +{ + struct ahash_request *req; + + req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash), + crypto_tfm_ctx_alignment()); + + ahash_request_set_tfm(req, ahash); + + return req; +} + +static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash, + struct ahash_request *req) +{ + return (void *)ALIGN((unsigned long)(req + 1) + + crypto_ahash_reqsize(ahash), + __alignof__(struct scatterlist)); +} /* Clear mutable options and find final destination to substitute * into IP header for icv calculation. Options are already checked @@ -54,20 +112,72 @@ static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) return 0; } +static void ah_output_done(struct crypto_async_request *base, int err) +{ + u8 *icv; + struct iphdr *iph; + struct sk_buff *skb = base->data; + struct xfrm_state *x = skb_dst(skb)->xfrm; + struct ah_data *ahp = x->data; + struct iphdr *top_iph = ip_hdr(skb); + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int ihl = ip_hdrlen(skb); + + iph = AH_SKB_CB(skb)->tmp; + icv = ah_tmp_icv(ahp->ahash, iph, ihl); + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + + top_iph->tos = iph->tos; + top_iph->ttl = iph->ttl; + top_iph->frag_off = iph->frag_off; + if (top_iph->ihl != 5) { + top_iph->daddr = iph->daddr; + memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); + } + + err = ah->nexthdr; + + kfree(AH_SKB_CB(skb)->tmp); + xfrm_output_resume(skb, err); +} + static int ah_output(struct xfrm_state *x, struct sk_buff *skb) { int err; + int nfrags; + int ihl; + u8 *icv; + struct sk_buff *trailer; + struct crypto_ahash *ahash; + struct ahash_request *req; + struct scatterlist *sg; struct iphdr *iph, *top_iph; struct ip_auth_hdr *ah; struct ah_data *ahp; - union { - struct iphdr iph; - char buf[60]; - } tmp_iph; + + ahp = x->data; + ahash = ahp->ahash; + + if ((err = skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + nfrags = err; skb_push(skb, -skb_network_offset(skb)); + ah = ip_auth_hdr(skb); + ihl = ip_hdrlen(skb); + + err = -ENOMEM; + iph = ah_alloc_tmp(ahash, nfrags, ihl); + if (!iph) + goto out; + + icv = ah_tmp_icv(ahash, iph, ihl); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + + memset(ah->auth_data, 0, ahp->icv_trunc_len); + top_iph = ip_hdr(skb); - iph = &tmp_iph.iph; iph->tos = top_iph->tos; iph->ttl = top_iph->ttl; @@ -78,10 +188,9 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); err = ip_clear_mutable_options(top_iph, &top_iph->daddr); if (err) - goto error; + goto out_free; } - ah = ip_auth_hdr(skb); ah->nexthdr = *skb_mac_header(skb); *skb_mac_header(skb) = IPPROTO_AH; @@ -91,20 +200,31 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->ttl = 0; top_iph->check = 0; - ahp = x->data; ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); - spin_lock_bh(&x->lock); - err = ah_mac_digest(ahp, skb, ah->auth_data); - memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); - spin_unlock_bh(&x->lock); + sg_init_table(sg, nfrags); + skb_to_sgvec(skb, sg, 0, skb->len); - if (err) - goto error; + ahash_request_set_crypt(req, sg, icv, skb->len); + ahash_request_set_callback(req, 0, ah_output_done, skb); + + AH_SKB_CB(skb)->tmp = iph; + + err = crypto_ahash_digest(req); + if (err) { + if (err == -EINPROGRESS) + goto out; + + if (err == -EBUSY) + err = NET_XMIT_DROP; + goto out_free; + } + + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; @@ -114,28 +234,67 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); } - err = 0; - -error: +out_free: + kfree(iph); +out: return err; } +static void ah_input_done(struct crypto_async_request *base, int err) +{ + u8 *auth_data; + u8 *icv; + struct iphdr *work_iph; + struct sk_buff *skb = base->data; + struct xfrm_state *x = xfrm_input_state(skb); + struct ah_data *ahp = x->data; + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int ihl = ip_hdrlen(skb); + int ah_hlen = (ah->hdrlen + 2) << 2; + + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, ihl); + icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); + + err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; + if (err) + goto out; + + skb->network_header += ah_hlen; + memcpy(skb_network_header(skb), work_iph, ihl); + __skb_pull(skb, ah_hlen + ihl); + skb_set_transport_header(skb, -ihl); + + err = ah->nexthdr; +out: + kfree(AH_SKB_CB(skb)->tmp); + xfrm_input_resume(skb, err); +} + static int ah_input(struct xfrm_state *x, struct sk_buff *skb) { int ah_hlen; int ihl; int nexthdr; - int err = -EINVAL; - struct iphdr *iph; + int nfrags; + u8 *auth_data; + u8 *icv; + struct sk_buff *trailer; + struct crypto_ahash *ahash; + struct ahash_request *req; + struct scatterlist *sg; + struct iphdr *iph, *work_iph; struct ip_auth_hdr *ah; struct ah_data *ahp; - char work_buf[60]; + int err = -ENOMEM; if (!pskb_may_pull(skb, sizeof(*ah))) goto out; ah = (struct ip_auth_hdr *)skb->data; ahp = x->data; + ahash = ahp->ahash; + nexthdr = ah->nexthdr; ah_hlen = (ah->hdrlen + 2) << 2; @@ -156,9 +315,24 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) ah = (struct ip_auth_hdr *)skb->data; iph = ip_hdr(skb); + ihl = ip_hdrlen(skb); + + if ((err = skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + nfrags = err; + + work_iph = ah_alloc_tmp(ahash, nfrags, ihl + ahp->icv_trunc_len); + if (!work_iph) + goto out; + + auth_data = ah_tmp_auth(work_iph, ihl); + icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); - ihl = skb->data - skb_network_header(skb); - memcpy(work_buf, iph, ihl); + memcpy(work_iph, iph, ihl); + memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); + memset(ah->auth_data, 0, ahp->icv_trunc_len); iph->ttl = 0; iph->tos = 0; @@ -166,35 +340,44 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) iph->check = 0; if (ihl > sizeof(*iph)) { __be32 dummy; - if (ip_clear_mutable_options(iph, &dummy)) - goto out; + err = ip_clear_mutable_options(iph, &dummy); + if (err) + goto out_free; } - spin_lock(&x->lock); - { - u8 auth_data[MAX_AH_AUTH_LEN]; + skb_push(skb, ihl); - memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); - skb_push(skb, ihl); - err = ah_mac_digest(ahp, skb, ah->auth_data); - if (err) - goto unlock; - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) - err = -EBADMSG; + sg_init_table(sg, nfrags); + skb_to_sgvec(skb, sg, 0, skb->len); + + ahash_request_set_crypt(req, sg, icv, skb->len); + ahash_request_set_callback(req, 0, ah_input_done, skb); + + AH_SKB_CB(skb)->tmp = work_iph; + + err = crypto_ahash_digest(req); + if (err) { + if (err == -EINPROGRESS) + goto out; + + if (err == -EBUSY) + err = NET_XMIT_DROP; + goto out_free; } -unlock: - spin_unlock(&x->lock); + err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; if (err) - goto out; + goto out_free; skb->network_header += ah_hlen; - memcpy(skb_network_header(skb), work_buf, ihl); - skb->transport_header = skb->network_header; + memcpy(skb_network_header(skb), work_iph, ihl); __skb_pull(skb, ah_hlen + ihl); + skb_set_transport_header(skb, -ihl); - return nexthdr; + err = nexthdr; +out_free: + kfree (work_iph); out: return err; } @@ -222,7 +405,7 @@ static int ah_init_state(struct xfrm_state *x) { struct ah_data *ahp = NULL; struct xfrm_algo_desc *aalg_desc; - struct crypto_hash *tfm; + struct crypto_ahash *ahash; if (!x->aalg) goto error; @@ -231,31 +414,31 @@ static int ah_init_state(struct xfrm_state *x) goto error; ahp = kzalloc(sizeof(*ahp), GFP_KERNEL); - if (ahp == NULL) + if (!ahp) return -ENOMEM; - tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) + ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0); + if (IS_ERR(ahash)) goto error; - ahp->tfm = tfm; - if (crypto_hash_setkey(tfm, x->aalg->alg_key, - (x->aalg->alg_key_len + 7) / 8)) + ahp->ahash = ahash; + if (crypto_ahash_setkey(ahash, x->aalg->alg_key, + (x->aalg->alg_key_len + 7) / 8)) goto error; /* * Lookup the algorithm description maintained by xfrm_algo, * verify crypto transform properties, and store information * we need for AH processing. This lookup cannot fail here - * after a successful crypto_alloc_hash(). + * after a successful crypto_alloc_ahash(). */ aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); BUG_ON(!aalg_desc); if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_hash_digestsize(tfm)) { + crypto_ahash_digestsize(ahash)) { printk(KERN_INFO "AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_hash_digestsize(tfm), + x->aalg->alg_name, crypto_ahash_digestsize(ahash), aalg_desc->uinfo.auth.icv_fullbits/8); goto error; } @@ -265,10 +448,6 @@ static int ah_init_state(struct xfrm_state *x) BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); - ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); - if (!ahp->work_icv) - goto error; - x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); if (x->props.mode == XFRM_MODE_TUNNEL) @@ -279,8 +458,7 @@ static int ah_init_state(struct xfrm_state *x) error: if (ahp) { - kfree(ahp->work_icv); - crypto_free_hash(ahp->tfm); + crypto_free_ahash(ahp->ahash); kfree(ahp); } return -EINVAL; @@ -293,8 +471,7 @@ static void ah_destroy(struct xfrm_state *x) if (!ahp) return; - kfree(ahp->work_icv); - crypto_free_hash(ahp->tfm); + crypto_free_ahash(ahp->ahash); kfree(ahp); } -- cgit v1.2.3 From 8631e9bdfea189b2e5efe3b03825cc24ebb6cfb7 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 7 Oct 2009 22:49:01 +0000 Subject: ah6: convert to ahash This patch converts ah6 to the new ahash interface. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- net/ipv6/ah6.c | 352 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 272 insertions(+), 80 deletions(-) (limited to 'net') diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index c1589e2f1dc..0f526f8ea51 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -24,18 +24,92 @@ * This file is derived from net/ipv4/ah.c. */ +#include #include #include #include #include #include -#include #include +#include #include #include #include #include +#define IPV6HDR_BASELEN 8 + +struct tmp_ext { +#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) + struct in6_addr saddr; +#endif + struct in6_addr daddr; + char hdrs[0]; +}; + +struct ah_skb_cb { + struct xfrm_skb_cb xfrm; + void *tmp; +}; + +#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0])) + +static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags, + unsigned int size) +{ + unsigned int len; + + len = size + crypto_ahash_digestsize(ahash) + + (crypto_ahash_alignmask(ahash) & + ~(crypto_tfm_ctx_alignment() - 1)); + + len = ALIGN(len, crypto_tfm_ctx_alignment()); + + len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash); + len = ALIGN(len, __alignof__(struct scatterlist)); + + len += sizeof(struct scatterlist) * nfrags; + + return kmalloc(len, GFP_ATOMIC); +} + +static inline struct tmp_ext *ah_tmp_ext(void *base) +{ + return base + IPV6HDR_BASELEN; +} + +static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset) +{ + return tmp + offset; +} + +static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, + unsigned int offset) +{ + return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); +} + +static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, + u8 *icv) +{ + struct ahash_request *req; + + req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash), + crypto_tfm_ctx_alignment()); + + ahash_request_set_tfm(req, ahash); + + return req; +} + +static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash, + struct ahash_request *req) +{ + return (void *)ALIGN((unsigned long)(req + 1) + + crypto_ahash_reqsize(ahash), + __alignof__(struct scatterlist)); +} + static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr) { u8 *opt = (u8 *)opthdr; @@ -218,24 +292,85 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) return 0; } +static void ah6_output_done(struct crypto_async_request *base, int err) +{ + int extlen; + u8 *iph_base; + u8 *icv; + struct sk_buff *skb = base->data; + struct xfrm_state *x = skb_dst(skb)->xfrm; + struct ah_data *ahp = x->data; + struct ipv6hdr *top_iph = ipv6_hdr(skb); + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + struct tmp_ext *iph_ext; + + extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr); + if (extlen) + extlen += sizeof(*iph_ext); + + iph_base = AH_SKB_CB(skb)->tmp; + iph_ext = ah_tmp_ext(iph_base); + icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen); + + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + memcpy(top_iph, iph_base, IPV6HDR_BASELEN); + + if (extlen) { +#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) + memcpy(&top_iph->saddr, iph_ext, extlen); +#else + memcpy(&top_iph->daddr, iph_ext, extlen); +#endif + } + + err = ah->nexthdr; + + kfree(AH_SKB_CB(skb)->tmp); + xfrm_output_resume(skb, err); +} + static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) { int err; + int nfrags; int extlen; + u8 *iph_base; + u8 *icv; + u8 nexthdr; + struct sk_buff *trailer; + struct crypto_ahash *ahash; + struct ahash_request *req; + struct scatterlist *sg; struct ipv6hdr *top_iph; struct ip_auth_hdr *ah; struct ah_data *ahp; - u8 nexthdr; - char tmp_base[8]; - struct { -#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) - struct in6_addr saddr; -#endif - struct in6_addr daddr; - char hdrs[0]; - } *tmp_ext; + struct tmp_ext *iph_ext; + + ahp = x->data; + ahash = ahp->ahash; + + if ((err = skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + nfrags = err; skb_push(skb, -skb_network_offset(skb)); + extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr); + if (extlen) + extlen += sizeof(*iph_ext); + + err = -ENOMEM; + iph_base = ah_alloc_tmp(ahash, nfrags, IPV6HDR_BASELEN + extlen); + if (!iph_base) + goto out; + + iph_ext = ah_tmp_ext(iph_base); + icv = ah_tmp_icv(ahash, iph_ext, extlen); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + + ah = ip_auth_hdr(skb); + memset(ah->auth_data, 0, ahp->icv_trunc_len); + top_iph = ipv6_hdr(skb); top_iph->payload_len = htons(skb->len - sizeof(*top_iph)); @@ -245,31 +380,22 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) /* When there are no extension headers, we only need to save the first * 8 bytes of the base IP header. */ - memcpy(tmp_base, top_iph, sizeof(tmp_base)); + memcpy(iph_base, top_iph, IPV6HDR_BASELEN); - tmp_ext = NULL; - extlen = skb_transport_offset(skb) - sizeof(struct ipv6hdr); if (extlen) { - extlen += sizeof(*tmp_ext); - tmp_ext = kmalloc(extlen, GFP_ATOMIC); - if (!tmp_ext) { - err = -ENOMEM; - goto error; - } #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) - memcpy(tmp_ext, &top_iph->saddr, extlen); + memcpy(iph_ext, &top_iph->saddr, extlen); #else - memcpy(tmp_ext, &top_iph->daddr, extlen); + memcpy(iph_ext, &top_iph->daddr, extlen); #endif err = ipv6_clear_mutable_options(top_iph, - extlen - sizeof(*tmp_ext) + + extlen - sizeof(*iph_ext) + sizeof(*top_iph), XFRM_POLICY_OUT); if (err) - goto error_free_iph; + goto out_free; } - ah = ip_auth_hdr(skb); ah->nexthdr = nexthdr; top_iph->priority = 0; @@ -278,36 +404,80 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->flow_lbl[2] = 0; top_iph->hop_limit = 0; - ahp = x->data; ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; ah->reserved = 0; ah->spi = x->id.spi; ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); - spin_lock_bh(&x->lock); - err = ah_mac_digest(ahp, skb, ah->auth_data); - memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); - spin_unlock_bh(&x->lock); + sg_init_table(sg, nfrags); + skb_to_sgvec(skb, sg, 0, skb->len); - if (err) - goto error_free_iph; + ahash_request_set_crypt(req, sg, icv, skb->len); + ahash_request_set_callback(req, 0, ah6_output_done, skb); + + AH_SKB_CB(skb)->tmp = iph_base; - memcpy(top_iph, tmp_base, sizeof(tmp_base)); - if (tmp_ext) { + err = crypto_ahash_digest(req); + if (err) { + if (err == -EINPROGRESS) + goto out; + + if (err == -EBUSY) + err = NET_XMIT_DROP; + goto out_free; + } + + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + memcpy(top_iph, iph_base, IPV6HDR_BASELEN); + + if (extlen) { #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) - memcpy(&top_iph->saddr, tmp_ext, extlen); + memcpy(&top_iph->saddr, iph_ext, extlen); #else - memcpy(&top_iph->daddr, tmp_ext, extlen); + memcpy(&top_iph->daddr, iph_ext, extlen); #endif -error_free_iph: - kfree(tmp_ext); } -error: +out_free: + kfree(iph_base); +out: return err; } +static void ah6_input_done(struct crypto_async_request *base, int err) +{ + u8 *auth_data; + u8 *icv; + u8 *work_iph; + struct sk_buff *skb = base->data; + struct xfrm_state *x = xfrm_input_state(skb); + struct ah_data *ahp = x->data; + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int hdr_len = skb_network_header_len(skb); + int ah_hlen = (ah->hdrlen + 2) << 2; + + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, hdr_len); + icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); + + err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; + if (err) + goto out; + + skb->network_header += ah_hlen; + memcpy(skb_network_header(skb), work_iph, hdr_len); + __skb_pull(skb, ah_hlen + hdr_len); + skb_set_transport_header(skb, -hdr_len); + + err = ah->nexthdr; +out: + kfree(AH_SKB_CB(skb)->tmp); + xfrm_input_resume(skb, err); +} + + + static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) { /* @@ -325,14 +495,21 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) * There is offset of AH before IPv6 header after the process. */ + u8 *auth_data; + u8 *icv; + u8 *work_iph; + struct sk_buff *trailer; + struct crypto_ahash *ahash; + struct ahash_request *req; + struct scatterlist *sg; struct ip_auth_hdr *ah; struct ipv6hdr *ip6h; struct ah_data *ahp; - unsigned char *tmp_hdr = NULL; u16 hdr_len; u16 ah_hlen; int nexthdr; - int err = -EINVAL; + int nfrags; + int err = -ENOMEM; if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) goto out; @@ -345,9 +522,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) skb->ip_summed = CHECKSUM_NONE; - hdr_len = skb->data - skb_network_header(skb); + hdr_len = skb_network_header_len(skb); ah = (struct ip_auth_hdr *)skb->data; ahp = x->data; + ahash = ahp->ahash; + nexthdr = ah->nexthdr; ah_hlen = (ah->hdrlen + 2) << 2; @@ -358,48 +537,67 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) if (!pskb_may_pull(skb, ah_hlen)) goto out; - tmp_hdr = kmemdup(skb_network_header(skb), hdr_len, GFP_ATOMIC); - if (!tmp_hdr) - goto out; ip6h = ipv6_hdr(skb); + + skb_push(skb, hdr_len); + + if ((err = skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + nfrags = err; + + work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len); + if (!work_iph) + goto out; + + auth_data = ah_tmp_auth(work_iph, hdr_len); + icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + + memcpy(work_iph, ip6h, hdr_len); + memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); + memset(ah->auth_data, 0, ahp->icv_trunc_len); + if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN)) - goto free_out; + goto out_free; + ip6h->priority = 0; ip6h->flow_lbl[0] = 0; ip6h->flow_lbl[1] = 0; ip6h->flow_lbl[2] = 0; ip6h->hop_limit = 0; - spin_lock(&x->lock); - { - u8 auth_data[MAX_AH_AUTH_LEN]; + sg_init_table(sg, nfrags); + skb_to_sgvec(skb, sg, 0, skb->len); - memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); - memset(ah->auth_data, 0, ahp->icv_trunc_len); - skb_push(skb, hdr_len); - err = ah_mac_digest(ahp, skb, ah->auth_data); - if (err) - goto unlock; - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) - err = -EBADMSG; + ahash_request_set_crypt(req, sg, icv, skb->len); + ahash_request_set_callback(req, 0, ah6_input_done, skb); + + AH_SKB_CB(skb)->tmp = work_iph; + + err = crypto_ahash_digest(req); + if (err) { + if (err == -EINPROGRESS) + goto out; + + if (err == -EBUSY) + err = NET_XMIT_DROP; + goto out_free; } -unlock: - spin_unlock(&x->lock); + err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; if (err) - goto free_out; + goto out_free; skb->network_header += ah_hlen; - memcpy(skb_network_header(skb), tmp_hdr, hdr_len); + memcpy(skb_network_header(skb), work_iph, hdr_len); skb->transport_header = skb->network_header; __skb_pull(skb, ah_hlen + hdr_len); - kfree(tmp_hdr); + err = nexthdr; - return nexthdr; - -free_out: - kfree(tmp_hdr); +out_free: + kfree(work_iph); out: return err; } @@ -430,7 +628,7 @@ static int ah6_init_state(struct xfrm_state *x) { struct ah_data *ahp = NULL; struct xfrm_algo_desc *aalg_desc; - struct crypto_hash *tfm; + struct crypto_ahash *ahash; if (!x->aalg) goto error; @@ -442,12 +640,12 @@ static int ah6_init_state(struct xfrm_state *x) if (ahp == NULL) return -ENOMEM; - tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) + ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0); + if (IS_ERR(ahash)) goto error; - ahp->tfm = tfm; - if (crypto_hash_setkey(tfm, x->aalg->alg_key, + ahp->ahash = ahash; + if (crypto_ahash_setkey(ahash, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8)) goto error; @@ -461,9 +659,9 @@ static int ah6_init_state(struct xfrm_state *x) BUG_ON(!aalg_desc); if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_hash_digestsize(tfm)) { + crypto_ahash_digestsize(ahash)) { printk(KERN_INFO "AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_hash_digestsize(tfm), + x->aalg->alg_name, crypto_ahash_digestsize(ahash), aalg_desc->uinfo.auth.icv_fullbits/8); goto error; } @@ -473,10 +671,6 @@ static int ah6_init_state(struct xfrm_state *x) BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); - ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); - if (!ahp->work_icv) - goto error; - x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); switch (x->props.mode) { @@ -495,8 +689,7 @@ static int ah6_init_state(struct xfrm_state *x) error: if (ahp) { - kfree(ahp->work_icv); - crypto_free_hash(ahp->tfm); + crypto_free_ahash(ahp->ahash); kfree(ahp); } return -EINVAL; @@ -509,8 +702,7 @@ static void ah6_destroy(struct xfrm_state *x) if (!ahp) return; - kfree(ahp->work_icv); - crypto_free_hash(ahp->tfm); + crypto_free_ahash(ahp->ahash); kfree(ahp); } -- cgit v1.2.3 From eb2ff967a587a4a784fd2390f38e324a5bec01ec Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Wed, 7 Oct 2009 22:50:40 +0000 Subject: xfrm: remove skb_icv_walk The last users of skb_icv_walk are converted to ahash now, so skb_icv_walk is unused and can be removed. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- include/net/xfrm.h | 3 -- net/xfrm/xfrm_algo.c | 78 ---------------------------------------------------- 2 files changed, 81 deletions(-) (limited to 'net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 223e90a4482..d9c6dbb9271 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1500,9 +1500,6 @@ struct scatterlist; typedef int (icv_update_fn_t)(struct hash_desc *, struct scatterlist *, unsigned int); -extern int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *tfm, - int offset, int len, icv_update_fn_t icv_update); - static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b, int family) { diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index faf54c6bf96..b39341072aa 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -689,84 +689,6 @@ int xfrm_count_enc_supported(void) } EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); -/* Move to common area: it is shared with AH. */ - -int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, - int offset, int len, icv_update_fn_t icv_update) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - struct scatterlist sg; - int err; - - /* Checksum header. */ - if (copy > 0) { - if (copy > len) - copy = len; - - sg_init_one(&sg, skb->data + offset, copy); - - err = icv_update(desc, &sg, copy); - if (unlikely(err)) - return err; - - if ((len -= copy) == 0) - return 0; - offset += copy; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - - WARN_ON(start > offset + len); - - end = start + skb_shinfo(skb)->frags[i].size; - if ((copy = end - offset) > 0) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - if (copy > len) - copy = len; - - sg_init_table(&sg, 1); - sg_set_page(&sg, frag->page, copy, - frag->page_offset + offset-start); - - err = icv_update(desc, &sg, copy); - if (unlikely(err)) - return err; - - if (!(len -= copy)) - return 0; - offset += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - err = skb_icv_walk(frag_iter, desc, offset-start, - copy, icv_update); - if (unlikely(err)) - return err; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; - } - BUG_ON(len); - return 0; -} -EXPORT_SYMBOL_GPL(skb_icv_walk); - #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) -- cgit v1.2.3 From c29eaf3faef7547ba72355bac44e9ca6ffdaee39 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 27 Aug 2009 17:54:53 -0700 Subject: wimax: indicate initial SW rfkill state is "blocked" The WiMAX stack assumes that all WiMAX devices are SW OFF when they are initialized. The recent changes in the RFKILL stack thus cause an initial call after rfkill_register(), because by default, rfkill considers devices to be SW ON upon registration. So call rfkill_init_sw_state() to set it to SW OFF so rfkill_register() doesn't do that unnecessary step. Signed-off-by: Inaky Perez-Gonzalez --- net/wimax/op-rfkill.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 70ef4df863b..40e1210cdbd 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -355,6 +355,7 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) wimax_dev->rfkill = rfkill; + rfkill_init_sw_state(rfkill, 1); result = rfkill_register(wimax_dev->rfkill); if (result < 0) goto error_rfkill_register; -- cgit v1.2.3 From 4c2b1a11646bf74e2926ce8b13a21884adc1e05c Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 2 Sep 2009 15:36:05 -0700 Subject: wimax: allow specifying debug levels as command line option Add "debug" module options to all the wimax modules (including drivers) so that the debug levels can be set upon kernel boot or module load time. This is needed as currently there was a limitation where the debug levels could only be set when a device was succesfully enumerated. This made it difficult to debug issues that made a device not probe properly. Signed-off-by: Inaky Perez-Gonzalez --- drivers/net/wimax/i2400m/driver.c | 10 ++++++ drivers/net/wimax/i2400m/sdio.c | 10 ++++++ drivers/net/wimax/i2400m/usb.c | 9 +++++ include/linux/wimax/debug.h | 72 +++++++++++++++++++++++++++++++++++++++ net/wimax/stack.c | 11 ++++++ 5 files changed, 112 insertions(+) (limited to 'net') diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 7ba00de5dd9..e3b2c246cad 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -90,6 +90,14 @@ MODULE_PARM_DESC(power_save_disabled, "False by default (so the device is told to do power " "saving)."); +static char i2400m_debug_params[128]; +module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params), + 0644); +MODULE_PARM_DESC(debug, + "String of space-separated NAME:VALUE pairs, where NAMEs " + "are the different debug submodules and VALUE are the " + "initial debug value to set."); + /** * i2400m_queue_work - schedule work on a i2400m's queue * @@ -794,6 +802,8 @@ size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); static int __init i2400m_driver_init(void) { + d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400m_debug_params, + "i2400m.debug"); return 0; } module_init(i2400m_driver_init); diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 7c1b843b63e..2d2cc5ac6d8 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -71,6 +71,14 @@ static int ioe_timeout = 2; module_param(ioe_timeout, int, 0); +static char i2400ms_debug_params[128]; +module_param_string(debug, i2400ms_debug_params, sizeof(i2400ms_debug_params), + 0644); +MODULE_PARM_DESC(debug, + "String of space-separated NAME:VALUE pairs, where NAMEs " + "are the different debug submodules and VALUE are the " + "initial debug value to set."); + /* Our firmware file name list */ static const char *i2400ms_bus_fw_names[] = { #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf" @@ -559,6 +567,8 @@ struct sdio_driver i2400m_sdio_driver = { static int __init i2400ms_driver_init(void) { + d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400ms_debug_params, + "i2400m_sdio.debug"); return sdio_register_driver(&i2400m_sdio_driver); } module_init(i2400ms_driver_init); diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index a5879e21bbf..063422290a4 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -71,6 +71,13 @@ #define D_SUBMODULE usb #include "usb-debug-levels.h" +static char i2400mu_debug_params[128]; +module_param_string(debug, i2400mu_debug_params, sizeof(i2400mu_debug_params), + 0644); +MODULE_PARM_DESC(debug, + "String of space-separated NAME:VALUE pairs, where NAMEs " + "are the different debug submodules and VALUE are the " + "initial debug value to set."); /* Our firmware file name */ static const char *i2400mu_bus_fw_names[] = { @@ -633,6 +640,8 @@ struct usb_driver i2400mu_driver = { static int __init i2400mu_driver_init(void) { + d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400mu_debug_params, + "i2400m_usb.debug"); return usb_register(&i2400mu_driver); } module_init(i2400mu_driver_init); diff --git a/include/linux/wimax/debug.h b/include/linux/wimax/debug.h index c703e034042..db8096e8853 100644 --- a/include/linux/wimax/debug.h +++ b/include/linux/wimax/debug.h @@ -450,4 +450,76 @@ do { \ }) +static inline +void d_submodule_set(struct d_level *d_level, size_t d_level_size, + const char *submodule, u8 level, const char *tag) +{ + struct d_level *itr, *top; + int index = -1; + + for (itr = d_level, top = itr + d_level_size; itr < top; itr++) { + index++; + if (itr->name == NULL) { + printk(KERN_ERR "%s: itr->name NULL?? (%p, #%d)\n", + tag, itr, index); + continue; + } + if (!strcmp(itr->name, submodule)) { + itr->level = level; + return; + } + } + printk(KERN_ERR "%s: unknown submodule %s\n", tag, submodule); +} + + +/** + * d_parse_params - Parse a string with debug parameters from the + * command line + * + * @d_level: level structure (D_LEVEL) + * @d_level_size: number of items in the level structure + * (D_LEVEL_SIZE). + * @_params: string with the parameters; this is a space (not tab!) + * separated list of NAME:VALUE, where value is the debug level + * and NAME is the name of the submodule. + * @tag: string for error messages (example: MODULE.ARGNAME). + */ +static inline +void d_parse_params(struct d_level *d_level, size_t d_level_size, + const char *_params, const char *tag) +{ + char submodule[130], *params, *params_orig, *token, *colon; + unsigned level, tokens; + + if (_params == NULL) + return; + params_orig = kstrdup(_params, GFP_KERNEL); + params = params_orig; + while (1) { + token = strsep(¶ms, " "); + if (token == NULL) + break; + if (*token == '\0') /* eat joint spaces */ + continue; + /* kernel's sscanf %s eats until whitespace, so we + * replace : by \n so it doesn't get eaten later by + * strsep */ + colon = strchr(token, ':'); + if (colon != NULL) + *colon = '\n'; + tokens = sscanf(token, "%s\n%u", submodule, &level); + if (colon != NULL) + *colon = ':'; /* set back, for error messages */ + if (tokens == 2) + d_submodule_set(d_level, d_level_size, + submodule, level, tag); + else + printk(KERN_ERR "%s: can't parse '%s' as a " + "SUBMODULE:LEVEL (%d tokens)\n", + tag, token, tokens); + } + kfree(params_orig); +} + #endif /* #ifndef __debug__h__ */ diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 79fb7d7c640..c8866412f83 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -60,6 +60,14 @@ #define D_SUBMODULE stack #include "debug-levels.h" +static char wimax_debug_params[128]; +module_param_string(debug, wimax_debug_params, sizeof(wimax_debug_params), + 0644); +MODULE_PARM_DESC(debug, + "String of space-separated NAME:VALUE pairs, where NAMEs " + "are the different debug submodules and VALUE are the " + "initial debug value to set."); + /* * Authoritative source for the RE_STATE_CHANGE attribute policy * @@ -562,6 +570,9 @@ int __init wimax_subsys_init(void) int result, cnt; d_fnstart(4, NULL, "()\n"); + d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params, + "wimax.debug"); + snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name), "WiMAX"); result = genl_register_family(&wimax_gnl_family); -- cgit v1.2.3 From de9315fa3a35ebe587cc1a1c88655d095846785e Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Wed, 30 Sep 2009 16:33:26 -0700 Subject: wimax: allow user space to send messages once the device is registered It makes sense that the messaging pipe to the device can be used before the device is fully ready, as long as it is registered with the stack. Some debugging tools need it. Signed-off-by: Inaky Perez-Gonzalez --- net/wimax/op-msg.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index d631a17186b..d3bfb6ef13a 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c @@ -388,6 +388,8 @@ int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info) } mutex_lock(&wimax_dev->mutex); result = wimax_dev_is_ready(wimax_dev); + if (result == -ENOMEDIUM) + result = 0; if (result < 0) goto error_not_ready; result = -ENOSYS; -- cgit v1.2.3 From 81d3f905389e22bb9a5176b9309c3f451c260e1a Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Sat, 3 Oct 2009 16:51:02 +0900 Subject: wimax: allow WIMAX_RF_QUERY calls when state is still uninitialized Until now, calls to wimax_rfkill() will be blocked until the device is at least past the WIMAX_ST_UNINITIALIZED state, return -ENOMEDIUM when the device is in the WIMAX_ST_DOWN state. In parallel, wimax-tools would issue a wimax_rfkill(WIMAX_RF_QUERY) call right after opening a handle with wimaxll_open() as means to verify if the interface is really a WiMAX interface [newer kernel version will have a call specifically for this]. The combination of these two facts is that in some cases, before the driver has finalized initializing its device's firmware, a wimaxll_open() call would fail, when it should not. Thus, change the wimax_rfkill() code to allow queries when the device is in WIMAX_ST_UNINITIALIZED state. Signed-off-by: Inaky Perez-Gonzalez --- net/wimax/op-rfkill.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 40e1210cdbd..94d339c345d 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -305,8 +305,15 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state) d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); mutex_lock(&wimax_dev->mutex); result = wimax_dev_is_ready(wimax_dev); - if (result < 0) + if (result < 0) { + /* While initializing, < 1.4.3 wimax-tools versions use + * this call to check if the device is a valid WiMAX + * device; so we allow it to proceed always, + * considering the radios are all off. */ + if (result == -ENOMEDIUM && state == WIMAX_RF_QUERY) + result = WIMAX_RF_OFF << 1 | WIMAX_RF_OFF; goto error_not_ready; + } switch (state) { case WIMAX_RF_ON: case WIMAX_RF_OFF: -- cgit v1.2.3 From 7e75f93eda027d9f9e0203ee6ffd210ea92e98f3 Mon Sep 17 00:00:00 2001 From: jamal Date: Mon, 19 Oct 2009 02:17:56 +0000 Subject: pkt_sched: ingress socket filter by mark Allow bpf to set a filter to drop packets that dont match a specific mark Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/filter.h | 3 ++- net/core/filter.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/filter.h b/include/linux/filter.h index 1354aaf6abb..909193e2539 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -123,7 +123,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ #define SKF_AD_IFINDEX 8 #define SKF_AD_NLATTR 12 #define SKF_AD_NLATTR_NEST 16 -#define SKF_AD_MAX 20 +#define SKF_AD_MARK 20 +#define SKF_AD_MAX 24 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/net/core/filter.c b/net/core/filter.c index d1d779ca096..e3987e1d483 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -303,6 +303,9 @@ load_b: case SKF_AD_IFINDEX: A = skb->dev->ifindex; continue; + case SKF_AD_MARK: + A = skb->mark; + continue; case SKF_AD_NLATTR: { struct nlattr *nla; -- cgit v1.2.3 From 0eae750e6019a93643063924209c1daf9cb9b4a7 Mon Sep 17 00:00:00 2001 From: John Dykstra Date: Mon, 19 Oct 2009 21:53:53 -0700 Subject: IP: Cleanups Use symbols instead of magic constants while checking PMTU discovery setsockopt. Remove redundant test in ip_rt_frag_needed() (done by caller). Signed-off-by: John Dykstra Signed-off-by: David S. Miller --- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/route.c | 3 --- net/ipv6/ipv6_sockglue.c | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index c602d985fe1..2445fedec0b 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -575,7 +575,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, inet->hdrincl = val ? 1 : 0; break; case IP_MTU_DISCOVER: - if (val < 0 || val > 3) + if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE) goto e_inval; inet->pmtudisc = val; break; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bb419925202..68fb2270205 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1628,9 +1628,6 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, __be32 daddr = iph->daddr; unsigned short est_mtu = 0; - if (ipv4_config.no_pmtu_disc) - return 0; - for (k = 0; k < 2; k++) { for (i = 0; i < 2; i++) { unsigned hash = rt_hash(daddr, skeys[i], ikeys[k], diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 39e10ac8801..68566de4bcc 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -662,7 +662,7 @@ done: case IPV6_MTU_DISCOVER: if (optlen < sizeof(int)) goto e_inval; - if (val<0 || val>3) + if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE) goto e_inval; np->pmtudisc = val; retv = 0; -- cgit v1.2.3 From 94b059520d6c0cea852dc9a3e9033c6f123df7c1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 16 Oct 2009 04:02:20 +0000 Subject: af_packet: Avoid cache line dirtying While doing multiple captures, I found af_packet was dirtying cache line containing its prot_hook. This slow down machines where several cpus are necessary to handle capture traffic, as each prot_hook is traversed for each packet coming in or out the host. This patches moves "struct packet_type prot_hook" to the end of packet_sock, and uses a ____cacheline_aligned_in_smp to make sure this remains shared by all cpus. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/packet/af_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index bf3a2954cd4..dac775e0bc7 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -188,7 +188,6 @@ struct packet_sock { struct packet_ring_buffer tx_ring; int copy_thresh; #endif - struct packet_type prot_hook; spinlock_t bind_lock; struct mutex pg_vec_lock; unsigned int running:1, /* prot_hook is attached*/ @@ -204,6 +203,7 @@ struct packet_sock { unsigned int tp_reserve; unsigned int tp_loss:1; #endif + struct packet_type prot_hook ____cacheline_aligned_in_smp; }; struct packet_skb_cb { -- cgit v1.2.3 From ad959e76f0fa94d299a8c25cb45de4d1b845e9ce Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 16 Oct 2009 06:38:46 +0000 Subject: af_packet: mc_drop/flush_mclist changes We hold RTNL, we can use __dev_get_by_index() instead of dev_get_by_index() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/packet/af_packet.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index dac775e0bc7..ff752c60641 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1664,11 +1664,9 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) if (--ml->count == 0) { struct net_device *dev; *mlp = ml->next; - dev = dev_get_by_index(sock_net(sk), ml->ifindex); - if (dev) { + dev = __dev_get_by_index(sock_net(sk), ml->ifindex); + if (dev) packet_dev_mc(dev, ml, -1); - dev_put(dev); - } kfree(ml); } rtnl_unlock(); @@ -1692,11 +1690,9 @@ static void packet_flush_mclist(struct sock *sk) struct net_device *dev; po->mclist = ml->next; - dev = dev_get_by_index(sock_net(sk), ml->ifindex); - if (dev != NULL) { + dev = __dev_get_by_index(sock_net(sk), ml->ifindex); + if (dev != NULL) packet_dev_mc(dev, ml, -1); - dev_put(dev); - } kfree(ml); } rtnl_unlock(); -- cgit v1.2.3 From d19742fb1c68e6db83b76e06dea5a374c99e104f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 20 Oct 2009 01:06:22 -0700 Subject: filter: Add SKF_AD_QUEUE instruction It can help being able to filter packets on their queue_mapping. If filter performance is not good, we could add a "numqueue" field in struct packet_type, so that netif_nit_deliver() and other functions can directly ignore packets with not expected queue number. Lets experiment this simple filter extension first. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/filter.h | 3 ++- net/core/filter.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/filter.h b/include/linux/filter.h index 909193e2539..bb3b4352978 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -124,7 +124,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ #define SKF_AD_NLATTR 12 #define SKF_AD_NLATTR_NEST 16 #define SKF_AD_MARK 20 -#define SKF_AD_MAX 24 +#define SKF_AD_QUEUE 24 +#define SKF_AD_MAX 28 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/net/core/filter.c b/net/core/filter.c index e3987e1d483..08db7b9143a 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -306,6 +306,9 @@ load_b: case SKF_AD_MARK: A = skb->mark; continue; + case SKF_AD_QUEUE: + A = skb->queue_mapping; + continue; case SKF_AD_NLATTR: { struct nlattr *nla; -- cgit v1.2.3 From e022f0b4a03f4fff9323b509df023b8af635716e Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 19 Oct 2009 23:46:20 +0000 Subject: net: Introduce sk_tx_queue_mapping Introduce sk_tx_queue_mapping; and functions that set, test and get this value. Reset sk_tx_queue_mapping to -1 whenever the dst cache is set/reset, and in socket alloc. Setting txq to -1 and using valid txq=<0 to n-1> allows the tx path to use the value of sk_tx_queue_mapping directly instead of subtracting 1 on every tx. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- include/net/sock.h | 26 ++++++++++++++++++++++++++ net/core/sock.c | 5 ++++- 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index 1364428f53f..55de3bd719a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -107,6 +107,7 @@ struct net; * @skc_node: main hash linkage for various protocol lookup tables * @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol * @skc_refcnt: reference count + * @skc_tx_queue_mapping: tx queue number for this connection * @skc_hash: hash value used with various protocol lookup tables * @skc_family: network address family * @skc_state: Connection state @@ -128,6 +129,7 @@ struct sock_common { struct hlist_nulls_node skc_nulls_node; }; atomic_t skc_refcnt; + int skc_tx_queue_mapping; unsigned int skc_hash; unsigned short skc_family; @@ -215,6 +217,7 @@ struct sock { #define sk_node __sk_common.skc_node #define sk_nulls_node __sk_common.skc_nulls_node #define sk_refcnt __sk_common.skc_refcnt +#define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping #define sk_copy_start __sk_common.skc_hash #define sk_hash __sk_common.skc_hash @@ -1094,8 +1097,29 @@ static inline void sock_put(struct sock *sk) extern int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested); +static inline void sk_tx_queue_set(struct sock *sk, int tx_queue) +{ + sk->sk_tx_queue_mapping = tx_queue; +} + +static inline void sk_tx_queue_clear(struct sock *sk) +{ + sk->sk_tx_queue_mapping = -1; +} + +static inline int sk_tx_queue_get(const struct sock *sk) +{ + return sk->sk_tx_queue_mapping; +} + +static inline bool sk_tx_queue_recorded(const struct sock *sk) +{ + return (sk && sk->sk_tx_queue_mapping >= 0); +} + static inline void sk_set_socket(struct sock *sk, struct socket *sock) { + sk_tx_queue_clear(sk); sk->sk_socket = sock; } @@ -1152,6 +1176,7 @@ __sk_dst_set(struct sock *sk, struct dst_entry *dst) { struct dst_entry *old_dst; + sk_tx_queue_clear(sk); old_dst = sk->sk_dst_cache; sk->sk_dst_cache = dst; dst_release(old_dst); @@ -1170,6 +1195,7 @@ __sk_dst_reset(struct sock *sk) { struct dst_entry *old_dst; + sk_tx_queue_clear(sk); old_dst = sk->sk_dst_cache; sk->sk_dst_cache = NULL; dst_release(old_dst); diff --git a/net/core/sock.c b/net/core/sock.c index 38713aa3faf..934d9673f08 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -357,6 +357,7 @@ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) struct dst_entry *dst = sk->sk_dst_cache; if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { + sk_tx_queue_clear(sk); sk->sk_dst_cache = NULL; dst_release(dst); return NULL; @@ -953,7 +954,8 @@ static void sock_copy(struct sock *nsk, const struct sock *osk) void *sptr = nsk->sk_security; #endif BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) != - sizeof(osk->sk_node) + sizeof(osk->sk_refcnt)); + sizeof(osk->sk_node) + sizeof(osk->sk_refcnt) + + sizeof(osk->sk_tx_queue_mapping)); memcpy(&nsk->sk_copy_start, &osk->sk_copy_start, osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start)); #ifdef CONFIG_SECURITY_NETWORK @@ -997,6 +999,7 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, if (!try_module_get(prot->owner)) goto out_free_sec; + sk_tx_queue_clear(sk); } return sk; -- cgit v1.2.3 From f04c8276248d3dd3e15a9a72f9711ba5e4069049 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 19 Oct 2009 23:46:32 +0000 Subject: net: IPv6 changes IPv6: Reset sk_tx_queue_mapping when dst_cache is reset. Use existing macro to do the work. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- net/ipv6/inet6_connection_sock.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 19dceef4fcc..3516e6fe2e5 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -168,8 +168,7 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) if (dst) { struct rt6_info *rt = (struct rt6_info *)dst; if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) { - sk->sk_dst_cache = NULL; - dst_release(dst); + __sk_dst_reset(sk); dst = NULL; } } -- cgit v1.2.3 From ea94ff3b55188df157a8740bdf3976a87563d705 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 19 Oct 2009 23:46:45 +0000 Subject: net: Fix for dst_negative_advice dst_negative_advice() should check for changed dst and reset sk_tx_queue_mapping accordingly. Pass sock to the callers of dst_negative_advice. (sk_reset_txq is defined just for use by dst_negative_advice. The only way I could find to get around this is to move dst_negative_() from dst.h to dst.c, include sock.h in dst.c, etc) Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- include/net/dst.h | 12 ++++++++++-- net/core/sock.c | 6 ++++++ net/dccp/timer.c | 4 ++-- net/decnet/af_decnet.c | 2 +- net/ipv4/tcp_timer.c | 4 ++-- 5 files changed, 21 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/dst.h b/include/net/dst.h index 5a900ddcf10..720d90653a8 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -222,11 +222,19 @@ static inline void dst_confirm(struct dst_entry *dst) neigh_confirm(dst->neighbour); } -static inline void dst_negative_advice(struct dst_entry **dst_p) +static inline void dst_negative_advice(struct dst_entry **dst_p, + struct sock *sk) { struct dst_entry * dst = *dst_p; - if (dst && dst->ops->negative_advice) + if (dst && dst->ops->negative_advice) { *dst_p = dst->ops->negative_advice(dst); + + if (dst != *dst_p) { + extern void sk_reset_txq(struct sock *sk); + + sk_reset_txq(sk); + } + } } static inline void dst_link_failure(struct sk_buff *skb) diff --git a/net/core/sock.c b/net/core/sock.c index 934d9673f08..5a51512f638 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -352,6 +352,12 @@ discard_and_relse: } EXPORT_SYMBOL(sk_receive_skb); +void sk_reset_txq(struct sock *sk) +{ + sk_tx_queue_clear(sk); +} +EXPORT_SYMBOL(sk_reset_txq); + struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) { struct dst_entry *dst = sk->sk_dst_cache; diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 162d1e683c3..bbfeb5eae46 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -38,7 +38,7 @@ static int dccp_write_timeout(struct sock *sk) if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) { if (icsk->icsk_retransmits != 0) - dst_negative_advice(&sk->sk_dst_cache); + dst_negative_advice(&sk->sk_dst_cache, sk); retry_until = icsk->icsk_syn_retries ? : sysctl_dccp_request_retries; } else { @@ -63,7 +63,7 @@ static int dccp_write_timeout(struct sock *sk) Golden words :-). */ - dst_negative_advice(&sk->sk_dst_cache); + dst_negative_advice(&sk->sk_dst_cache, sk); } retry_until = sysctl_dccp_retries2; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 4d3060660a1..664965c87e1 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1955,7 +1955,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, } if ((flags & MSG_TRYHARD) && sk->sk_dst_cache) - dst_negative_advice(&sk->sk_dst_cache); + dst_negative_advice(&sk->sk_dst_cache, sk); mss = scp->segsize_rem; fctype = scp->services_rem & NSP_FC_MASK; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 6e8996cb79d..8353a538cd4 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -141,14 +141,14 @@ static int tcp_write_timeout(struct sock *sk) if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { if (icsk->icsk_retransmits) - dst_negative_advice(&sk->sk_dst_cache); + dst_negative_advice(&sk->sk_dst_cache, sk); retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries; } else { if (retransmits_timed_out(sk, sysctl_tcp_retries1)) { /* Black hole detection */ tcp_mtu_probing(icsk, sk); - dst_negative_advice(&sk->sk_dst_cache); + dst_negative_advice(&sk->sk_dst_cache, sk); } retry_until = sysctl_tcp_retries2; -- cgit v1.2.3 From a4ee3ce3293dc931fab19beb472a8bde1295aebe Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 19 Oct 2009 23:50:07 +0000 Subject: net: Use sk_tx_queue_mapping for connected sockets For connected sockets, the first run of dev_pick_tx saves the calculated txq in sk_tx_queue_mapping. This is not saved if either the device has a queue select or the socket is not connected. Next iterations of dev_pick_tx uses the cached value of sk_tx_queue_mapping. Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- net/core/dev.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 28b0b9e992a..fa88dcd476d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1791,13 +1791,25 @@ EXPORT_SYMBOL(skb_tx_hash); static struct netdev_queue *dev_pick_tx(struct net_device *dev, struct sk_buff *skb) { - const struct net_device_ops *ops = dev->netdev_ops; - u16 queue_index = 0; + u16 queue_index; + struct sock *sk = skb->sk; + + if (sk_tx_queue_recorded(sk)) { + queue_index = sk_tx_queue_get(sk); + } else { + const struct net_device_ops *ops = dev->netdev_ops; - if (ops->ndo_select_queue) - queue_index = ops->ndo_select_queue(dev, skb); - else if (dev->real_num_tx_queues > 1) - queue_index = skb_tx_hash(dev, skb); + if (ops->ndo_select_queue) { + queue_index = ops->ndo_select_queue(dev, skb); + } else { + queue_index = 0; + if (dev->real_num_tx_queues > 1) + queue_index = skb_tx_hash(dev, skb); + + if (sk && sk->sk_dst_cache) + sk_tx_queue_set(sk, queue_index); + } + } skb_set_queue_mapping(skb, queue_index); return netdev_get_tx_queue(dev, queue_index); -- cgit v1.2.3 From a3d1289126e7b14307074b76bf1677015ea5036f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Oct 2009 10:59:31 +0000 Subject: rtnetlink: rtnl_setlink() and rtnl_getlink() changes rtnl_getlink() & rtnl_setlink() run with RTNL held, we can use __dev_get_by_index() and __dev_get_by_name() variants and avoid dev_hold()/dev_put() Adds to rtnl_getlink() the capability to find a device by its name, not only by its index. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index eb42873f2a3..ba13b0974a7 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -910,9 +910,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) err = -EINVAL; ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) - dev = dev_get_by_index(net, ifm->ifi_index); + dev = __dev_get_by_index(net, ifm->ifi_index); else if (tb[IFLA_IFNAME]) - dev = dev_get_by_name(net, ifname); + dev = __dev_get_by_name(net, ifname); else goto errout; @@ -922,11 +922,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) } if ((err = validate_linkmsg(dev, tb)) < 0) - goto errout_dev; + goto errout; err = do_setlink(dev, ifm, tb, ifname, 0); -errout_dev: - dev_put(dev); errout: return err; } @@ -1154,6 +1152,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; + char ifname[IFNAMSIZ]; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; struct sk_buff *nskb; @@ -1163,19 +1162,23 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (err < 0) return err; + if (tb[IFLA_IFNAME]) + nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); + ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) { - dev = dev_get_by_index(net, ifm->ifi_index); - if (dev == NULL) - return -ENODEV; - } else + if (ifm->ifi_index > 0) + dev = __dev_get_by_index(net, ifm->ifi_index); + else if (tb[IFLA_IFNAME]) + dev = __dev_get_by_name(net, ifname); + else return -EINVAL; + if (dev == NULL) + return -ENODEV; + nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); - if (nskb == NULL) { - err = -ENOBUFS; - goto errout; - } + if (nskb == NULL) + return -ENOBUFS; err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); @@ -1183,11 +1186,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) /* -EMSGSIZE implies BUG in if_nlmsg_size */ WARN_ON(err == -EMSGSIZE); kfree_skb(nskb); - goto errout; - } - err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid); -errout: - dev_put(dev); + } else + err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid); return err; } -- cgit v1.2.3 From 1c55d62e77fa16cdace417834fc7b8a421a1877f Mon Sep 17 00:00:00 2001 From: jamal Date: Thu, 15 Oct 2009 03:09:18 +0000 Subject: pkt_sched: skbedit add support for setting mark This adds support for setting the skb mark. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/tc_act/tc_skbedit.h | 2 ++ include/net/tc_act/tc_skbedit.h | 2 ++ net/sched/act_skbedit.c | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h index a14e461a7af..7a2e910a5f0 100644 --- a/include/linux/tc_act/tc_skbedit.h +++ b/include/linux/tc_act/tc_skbedit.h @@ -26,6 +26,7 @@ #define SKBEDIT_F_PRIORITY 0x1 #define SKBEDIT_F_QUEUE_MAPPING 0x2 +#define SKBEDIT_F_MARK 0x4 struct tc_skbedit { tc_gen; @@ -37,6 +38,7 @@ enum { TCA_SKBEDIT_PARMS, TCA_SKBEDIT_PRIORITY, TCA_SKBEDIT_QUEUE_MAPPING, + TCA_SKBEDIT_MARK, __TCA_SKBEDIT_MAX }; #define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1) diff --git a/include/net/tc_act/tc_skbedit.h b/include/net/tc_act/tc_skbedit.h index 6abb3ed3ebf..e103fe02f37 100644 --- a/include/net/tc_act/tc_skbedit.h +++ b/include/net/tc_act/tc_skbedit.h @@ -26,7 +26,9 @@ struct tcf_skbedit { struct tcf_common common; u32 flags; u32 priority; + u32 mark; u16 queue_mapping; + /* XXX: 16-bit pad here? */ }; #define to_skbedit(pc) \ container_of(pc, struct tcf_skbedit, common) diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 4ab916b8074..e9607fe55b5 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -54,6 +54,8 @@ static int tcf_skbedit(struct sk_buff *skb, struct tc_action *a, if (d->flags & SKBEDIT_F_QUEUE_MAPPING && skb->dev->real_num_tx_queues > d->queue_mapping) skb_set_queue_mapping(skb, d->queue_mapping); + if (d->flags & SKBEDIT_F_MARK) + skb->mark = d->mark; spin_unlock(&d->tcf_lock); return d->tcf_action; @@ -63,6 +65,7 @@ static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = { [TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) }, [TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) }, [TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) }, + [TCA_SKBEDIT_MARK] = { .len = sizeof(u32) }, }; static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est, @@ -72,7 +75,7 @@ static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est, struct tc_skbedit *parm; struct tcf_skbedit *d; struct tcf_common *pc; - u32 flags = 0, *priority = NULL; + u32 flags = 0, *priority = NULL, *mark = NULL; u16 *queue_mapping = NULL; int ret = 0, err; @@ -95,6 +98,12 @@ static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est, flags |= SKBEDIT_F_QUEUE_MAPPING; queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]); } + + if (tb[TCA_SKBEDIT_MARK] != NULL) { + flags |= SKBEDIT_F_MARK; + mark = nla_data(tb[TCA_SKBEDIT_MARK]); + } + if (!flags) return -EINVAL; @@ -124,6 +133,9 @@ static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est, d->priority = *priority; if (flags & SKBEDIT_F_QUEUE_MAPPING) d->queue_mapping = *queue_mapping; + if (flags & SKBEDIT_F_MARK) + d->mark = *mark; + d->tcf_action = parm->action; spin_unlock_bh(&d->tcf_lock); @@ -161,6 +173,9 @@ static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, if (d->flags & SKBEDIT_F_QUEUE_MAPPING) NLA_PUT(skb, TCA_SKBEDIT_QUEUE_MAPPING, sizeof(d->queue_mapping), &d->queue_mapping); + if (d->flags & SKBEDIT_F_MARK) + NLA_PUT(skb, TCA_SKBEDIT_MARK, sizeof(d->mark), + &d->mark); t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(d->tcf_tm.expires); -- cgit v1.2.3 From ef9a9d1183b36fbf3de327f44596533b770c3005 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Oct 2009 17:51:26 +0000 Subject: ipv6 sit: RCU conversion phase I SIT tunnels use one rwlock to protect their prl entries. This first patch adds RCU locking for prl management, with standard call_rcu() calls. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/ipip.h | 1 + net/ipv6/sit.c | 73 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/include/net/ipip.h b/include/net/ipip.h index 86f1c8bd040..b3db2fd6e61 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -45,6 +45,7 @@ struct ip_tunnel_prl_entry struct ip_tunnel_prl_entry *next; __be32 addr; u16 flags; + struct rcu_head rcu_head; }; #define IPTUNNEL_XMIT() do { \ diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 510d31f3cb9..8cdcc2ad048 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -240,15 +240,22 @@ failed: return NULL; } +static DEFINE_SPINLOCK(ipip6_prl_lock); + +#define for_each_prl_rcu(start) \ + for (prl = rcu_dereference(start); \ + prl; \ + prl = rcu_dereference(prl->next)) + static struct ip_tunnel_prl_entry * __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) { - struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; + struct ip_tunnel_prl_entry *prl; - for (p = t->prl; p; p = p->next) - if (p->addr == addr) + for_each_prl_rcu(t->prl) + if (prl->addr == addr) break; - return p; + return prl; } @@ -273,7 +280,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, kcalloc(cmax, sizeof(*kp), GFP_KERNEL) : NULL; - read_lock(&ipip6_lock); + rcu_read_lock(); ca = t->prl_count < cmax ? t->prl_count : cmax; @@ -291,7 +298,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, } c = 0; - for (prl = t->prl; prl; prl = prl->next) { + for_each_prl_rcu(t->prl) { if (c >= cmax) break; if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) @@ -303,7 +310,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, break; } out: - read_unlock(&ipip6_lock); + rcu_read_unlock(); len = sizeof(*kp) * c; ret = 0; @@ -324,12 +331,14 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) if (a->addr == htonl(INADDR_ANY)) return -EINVAL; - write_lock(&ipip6_lock); + spin_lock(&ipip6_prl_lock); for (p = t->prl; p; p = p->next) { if (p->addr == a->addr) { - if (chg) - goto update; + if (chg) { + p->flags = a->flags; + goto out; + } err = -EEXIST; goto out; } @@ -346,46 +355,63 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) goto out; } + INIT_RCU_HEAD(&p->rcu_head); p->next = t->prl; - t->prl = p; - t->prl_count++; -update: p->addr = a->addr; p->flags = a->flags; + t->prl_count++; + rcu_assign_pointer(t->prl, p); out: - write_unlock(&ipip6_lock); + spin_unlock(&ipip6_prl_lock); return err; } +static void prl_entry_destroy_rcu(struct rcu_head *head) +{ + kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head)); +} + +static void prl_list_destroy_rcu(struct rcu_head *head) +{ + struct ip_tunnel_prl_entry *p, *n; + + p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); + do { + n = p->next; + kfree(p); + p = n; + } while (p); +} + static int ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) { struct ip_tunnel_prl_entry *x, **p; int err = 0; - write_lock(&ipip6_lock); + spin_lock(&ipip6_prl_lock); if (a && a->addr != htonl(INADDR_ANY)) { for (p = &t->prl; *p; p = &(*p)->next) { if ((*p)->addr == a->addr) { x = *p; *p = x->next; - kfree(x); + call_rcu(&x->rcu_head, prl_entry_destroy_rcu); t->prl_count--; goto out; } } err = -ENXIO; } else { - while (t->prl) { + if (t->prl) { + t->prl_count = 0; x = t->prl; - t->prl = t->prl->next; - kfree(x); - t->prl_count--; + call_rcu(&x->rcu_head, prl_list_destroy_rcu); + t->prl = NULL; } } out: - write_unlock(&ipip6_lock); + spin_unlock(&ipip6_prl_lock); return err; } @@ -395,7 +421,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) struct ip_tunnel_prl_entry *p; int ok = 1; - read_lock(&ipip6_lock); + rcu_read_lock(); p = __ipip6_tunnel_locate_prl(t, iph->saddr); if (p) { if (p->flags & PRL_DEFAULT) @@ -411,7 +437,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) else ok = 0; } - read_unlock(&ipip6_lock); + rcu_read_unlock(); return ok; } @@ -1192,6 +1218,7 @@ static void __exit sit_cleanup(void) xfrm4_tunnel_deregister(&sit_handler, AF_INET6); unregister_pernet_gen_device(sit_net_id, &sit_net_ops); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ } static int __init sit_init(void) -- cgit v1.2.3 From 4543c10de267bdd4f9acdb7708456909ed7eed3c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Oct 2009 17:52:14 +0000 Subject: ipv6 sit: RCU conversion phase II SIT tunnels use one rwlock to protect their hash tables. This locking scheme can be converted to RCU for free, since netdevice already must wait for a RCU grace period at dismantle time. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/sit.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 8cdcc2ad048..b6b16264b30 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -77,8 +77,17 @@ struct sit_net { struct net_device *fb_tunnel_dev; }; -static DEFINE_RWLOCK(ipip6_lock); +/* + * Locking : hash tables are protected by RCU and a spinlock + */ +static DEFINE_SPINLOCK(ipip6_lock); + +#define for_each_ip_tunnel_rcu(start) \ + for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) +/* + * Must be invoked with rcu_read_lock + */ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, struct net_device *dev, __be32 remote, __be32 local) { @@ -87,26 +96,26 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, struct ip_tunnel *t; struct sit_net *sitn = net_generic(net, sit_net_id); - for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { + for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && (!dev || !t->parms.link || dev->iflink == t->parms.link) && (t->dev->flags & IFF_UP)) return t; } - for (t = sitn->tunnels_r[h0]; t; t = t->next) { + for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) { if (remote == t->parms.iph.daddr && (!dev || !t->parms.link || dev->iflink == t->parms.link) && (t->dev->flags & IFF_UP)) return t; } - for (t = sitn->tunnels_l[h1]; t; t = t->next) { + for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) { if (local == t->parms.iph.saddr && (!dev || !t->parms.link || dev->iflink == t->parms.link) && (t->dev->flags & IFF_UP)) return t; } - t = sitn->tunnels_wc[0]; + t = rcu_dereference(sitn->tunnels_wc[0]); if ((t != NULL) && (t->dev->flags & IFF_UP)) return t; return NULL; @@ -143,9 +152,9 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { if (t == *tp) { - write_lock_bh(&ipip6_lock); + spin_lock_bh(&ipip6_lock); *tp = t->next; - write_unlock_bh(&ipip6_lock); + spin_unlock_bh(&ipip6_lock); break; } } @@ -155,10 +164,10 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) { struct ip_tunnel **tp = ipip6_bucket(sitn, t); + spin_lock_bh(&ipip6_lock); t->next = *tp; - write_lock_bh(&ipip6_lock); - *tp = t; - write_unlock_bh(&ipip6_lock); + rcu_assign_pointer(*tp, t); + spin_unlock_bh(&ipip6_lock); } static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) @@ -447,9 +456,9 @@ static void ipip6_tunnel_uninit(struct net_device *dev) struct sit_net *sitn = net_generic(net, sit_net_id); if (dev == sitn->fb_tunnel_dev) { - write_lock_bh(&ipip6_lock); + spin_lock_bh(&ipip6_lock); sitn->tunnels_wc[0] = NULL; - write_unlock_bh(&ipip6_lock); + spin_unlock_bh(&ipip6_lock); dev_put(dev); } else { ipip6_tunnel_unlink(sitn, netdev_priv(dev)); @@ -502,7 +511,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) err = -ENOENT; - read_lock(&ipip6_lock); + rcu_read_lock(); t = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, iph->daddr, @@ -520,7 +529,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) t->err_count = 1; t->err_time = jiffies; out: - read_unlock(&ipip6_lock); + rcu_read_unlock(); return err; } @@ -540,7 +549,7 @@ static int ipip6_rcv(struct sk_buff *skb) iph = ip_hdr(skb); - read_lock(&ipip6_lock); + rcu_read_lock(); tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, iph->saddr, iph->daddr); if (tunnel != NULL) { @@ -554,7 +563,7 @@ static int ipip6_rcv(struct sk_buff *skb) if ((tunnel->dev->priv_flags & IFF_ISATAP) && !isatap_chksrc(skb, iph, tunnel)) { tunnel->dev->stats.rx_errors++; - read_unlock(&ipip6_lock); + rcu_read_unlock(); kfree_skb(skb); return 0; } @@ -565,12 +574,12 @@ static int ipip6_rcv(struct sk_buff *skb) nf_reset(skb); ipip6_ecn_decapsulate(iph, skb); netif_rx(skb); - read_unlock(&ipip6_lock); + rcu_read_unlock(); return 0; } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - read_unlock(&ipip6_lock); + rcu_read_unlock(); out: kfree_skb(skb); return 0; -- cgit v1.2.3 From 91cc3bb0b04ffef49bb044e06b221ea5de053e91 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Oct 2009 18:19:19 +0000 Subject: xfrm6_tunnel: RCU conversion xfrm6_tunnels use one rwlock to protect their hash tables. Plain and straightforward conversion to RCU locking to permit better SMP performance. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/xfrm6_tunnel.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 81a95c00e50..438831d3359 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -23,7 +23,7 @@ */ #include #include -#include +#include #include #include #include @@ -36,14 +36,15 @@ * per xfrm_address_t. */ struct xfrm6_tunnel_spi { - struct hlist_node list_byaddr; - struct hlist_node list_byspi; - xfrm_address_t addr; - u32 spi; - atomic_t refcnt; + struct hlist_node list_byaddr; + struct hlist_node list_byspi; + xfrm_address_t addr; + u32 spi; + atomic_t refcnt; + struct rcu_head rcu_head; }; -static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); +static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); static u32 xfrm6_tunnel_spi; @@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void) if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) return; } + rcu_barrier(); kmem_cache_destroy(xfrm6_tunnel_spi_kmem); xfrm6_tunnel_spi_kmem = NULL; } @@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) struct xfrm6_tunnel_spi *x6spi; struct hlist_node *pos; - hlist_for_each_entry(x6spi, pos, + hlist_for_each_entry_rcu(x6spi, pos, &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], list_byaddr) { if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) @@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) struct xfrm6_tunnel_spi *x6spi; u32 spi; - read_lock_bh(&xfrm6_tunnel_spi_lock); + rcu_read_lock_bh(); x6spi = __xfrm6_tunnel_spi_lookup(saddr); spi = x6spi ? x6spi->spi : 0; - read_unlock_bh(&xfrm6_tunnel_spi_lock); + rcu_read_unlock_bh(); return htonl(spi); } @@ -185,14 +187,15 @@ alloc_spi: if (!x6spi) goto out; + INIT_RCU_HEAD(&x6spi->rcu_head); memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); x6spi->spi = spi; atomic_set(&x6spi->refcnt, 1); - hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); + hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); index = xfrm6_tunnel_spi_hash_byaddr(saddr); - hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); + hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); out: return spi; } @@ -202,26 +205,32 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) struct xfrm6_tunnel_spi *x6spi; u32 spi; - write_lock_bh(&xfrm6_tunnel_spi_lock); + spin_lock_bh(&xfrm6_tunnel_spi_lock); x6spi = __xfrm6_tunnel_spi_lookup(saddr); if (x6spi) { atomic_inc(&x6spi->refcnt); spi = x6spi->spi; } else spi = __xfrm6_tunnel_alloc_spi(saddr); - write_unlock_bh(&xfrm6_tunnel_spi_lock); + spin_unlock_bh(&xfrm6_tunnel_spi_lock); return htonl(spi); } EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); +static void x6spi_destroy_rcu(struct rcu_head *head) +{ + kmem_cache_free(xfrm6_tunnel_spi_kmem, + container_of(head, struct xfrm6_tunnel_spi, rcu_head)); +} + void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) { struct xfrm6_tunnel_spi *x6spi; struct hlist_node *pos, *n; - write_lock_bh(&xfrm6_tunnel_spi_lock); + spin_lock_bh(&xfrm6_tunnel_spi_lock); hlist_for_each_entry_safe(x6spi, pos, n, &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], @@ -229,14 +238,14 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) { if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { if (atomic_dec_and_test(&x6spi->refcnt)) { - hlist_del(&x6spi->list_byaddr); - hlist_del(&x6spi->list_byspi); - kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi); + hlist_del_rcu(&x6spi->list_byaddr); + hlist_del_rcu(&x6spi->list_byspi); + call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu); break; } } } - write_unlock_bh(&xfrm6_tunnel_spi_lock); + spin_unlock_bh(&xfrm6_tunnel_spi_lock); } EXPORT_SYMBOL(xfrm6_tunnel_free_spi); -- cgit v1.2.3 From 8f95dd63a2ab6fe7243c4f0bd2c3266e3a5525ab Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Oct 2009 05:42:02 +0000 Subject: ipip: convert hash tables locking to RCU IPIP tunnels use one rwlock to protect their hash tables. This locking scheme can be converted to RCU for free, since netdevice already must wait for a RCU grace period at dismantle time. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 6a5539236ab..3bd69988bcc 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -134,7 +134,13 @@ static void ipip_fb_tunnel_init(struct net_device *dev); static void ipip_tunnel_init(struct net_device *dev); static void ipip_tunnel_setup(struct net_device *dev); -static DEFINE_RWLOCK(ipip_lock); +/* + * Locking : hash tables are protected by RCU and a spinlock + */ +static DEFINE_SPINLOCK(ipip_lock); + +#define for_each_ip_tunnel_rcu(start) \ + for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, __be32 remote, __be32 local) @@ -144,20 +150,21 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, struct ip_tunnel *t; struct ipip_net *ipn = net_generic(net, ipip_net_id); - for (t = ipn->tunnels_r_l[h0^h1]; t; t = t->next) { + for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1]) if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; - } - for (t = ipn->tunnels_r[h0]; t; t = t->next) { + + for_each_ip_tunnel_rcu(ipn->tunnels_r[h0]) if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; - } - for (t = ipn->tunnels_l[h1]; t; t = t->next) { + + for_each_ip_tunnel_rcu(ipn->tunnels_l[h1]) if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) return t; - } - if ((t = ipn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) + + t = rcu_dereference(ipn->tunnels_wc[0]); + if (t && (t->dev->flags&IFF_UP)) return t; return NULL; } @@ -193,9 +200,9 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t) for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) { if (t == *tp) { - write_lock_bh(&ipip_lock); + spin_lock_bh(&ipip_lock); *tp = t->next; - write_unlock_bh(&ipip_lock); + spin_unlock_bh(&ipip_lock); break; } } @@ -205,10 +212,10 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t) { struct ip_tunnel **tp = ipip_bucket(ipn, t); + spin_lock_bh(&ipip_lock); t->next = *tp; - write_lock_bh(&ipip_lock); - *tp = t; - write_unlock_bh(&ipip_lock); + rcu_assign_pointer(*tp, t); + spin_unlock_bh(&ipip_lock); } static struct ip_tunnel * ipip_tunnel_locate(struct net *net, @@ -267,9 +274,9 @@ static void ipip_tunnel_uninit(struct net_device *dev) struct ipip_net *ipn = net_generic(net, ipip_net_id); if (dev == ipn->fb_tunnel_dev) { - write_lock_bh(&ipip_lock); + spin_lock_bh(&ipip_lock); ipn->tunnels_wc[0] = NULL; - write_unlock_bh(&ipip_lock); + spin_unlock_bh(&ipip_lock); } else ipip_tunnel_unlink(ipn, netdev_priv(dev)); dev_put(dev); @@ -318,7 +325,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) err = -ENOENT; - read_lock(&ipip_lock); + rcu_read_lock(); t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -333,7 +340,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) t->err_count = 1; t->err_time = jiffies; out: - read_unlock(&ipip_lock); + rcu_read_unlock(); return err; } @@ -351,11 +358,11 @@ static int ipip_rcv(struct sk_buff *skb) struct ip_tunnel *tunnel; const struct iphdr *iph = ip_hdr(skb); - read_lock(&ipip_lock); + rcu_read_lock(); if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr)) != NULL) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - read_unlock(&ipip_lock); + rcu_read_unlock(); kfree_skb(skb); return 0; } @@ -374,10 +381,10 @@ static int ipip_rcv(struct sk_buff *skb) nf_reset(skb); ipip_ecn_decapsulate(iph, skb); netif_rx(skb); - read_unlock(&ipip_lock); + rcu_read_unlock(); return 0; } - read_unlock(&ipip_lock); + rcu_read_unlock(); return -1; } -- cgit v1.2.3 From 2922bc8aedfcd41ca6171cfe1a79ff111ad72019 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Oct 2009 06:34:34 +0000 Subject: ip6tnl: convert hash tables locking to RCU ip6_tunnels use one rwlock to protect their hash tables. This locking scheme can be converted to RCU for free, since netdevice already must wait for a RCU grace period at dismantle time. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index c595bbe1ed9..670c291d256 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -88,8 +88,10 @@ struct ip6_tnl_net { struct ip6_tnl **tnls[2]; }; -/* lock for the tunnel lists */ -static DEFINE_RWLOCK(ip6_tnl_lock); +/* + * Locking : hash tables are protected by RCU and a spinlock + */ +static DEFINE_SPINLOCK(ip6_tnl_lock); static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) { @@ -130,6 +132,9 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) * else %NULL **/ +#define for_each_ip6_tunnel_rcu(start) \ + for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) + static struct ip6_tnl * ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) { @@ -138,13 +143,14 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) struct ip6_tnl *t; struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) { + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) { if (ipv6_addr_equal(local, &t->parms.laddr) && ipv6_addr_equal(remote, &t->parms.raddr) && (t->dev->flags & IFF_UP)) return t; } - if ((t = ip6n->tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) + t = rcu_dereference(ip6n->tnls_wc[0]); + if (t && (t->dev->flags & IFF_UP)) return t; return NULL; @@ -186,10 +192,10 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) { struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); + spin_lock_bh(&ip6_tnl_lock); t->next = *tp; - write_lock_bh(&ip6_tnl_lock); - *tp = t; - write_unlock_bh(&ip6_tnl_lock); + rcu_assign_pointer(*tp, t); + spin_unlock_bh(&ip6_tnl_lock); } /** @@ -204,9 +210,9 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { if (t == *tp) { - write_lock_bh(&ip6_tnl_lock); + spin_lock_bh(&ip6_tnl_lock); *tp = t->next; - write_unlock_bh(&ip6_tnl_lock); + spin_unlock_bh(&ip6_tnl_lock); break; } } @@ -313,9 +319,9 @@ ip6_tnl_dev_uninit(struct net_device *dev) struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); if (dev == ip6n->fb_tnl_dev) { - write_lock_bh(&ip6_tnl_lock); + spin_lock_bh(&ip6_tnl_lock); ip6n->tnls_wc[0] = NULL; - write_unlock_bh(&ip6_tnl_lock); + spin_unlock_bh(&ip6_tnl_lock); } else { ip6_tnl_unlink(ip6n, t); } @@ -409,7 +415,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, in trouble since we might need the source address for further processing of the error. */ - read_lock(&ip6_tnl_lock); + rcu_read_lock(); if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, &ipv6h->saddr)) == NULL) goto out; @@ -482,7 +488,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, *msg = rel_msg; out: - read_unlock(&ip6_tnl_lock); + rcu_read_unlock(); return err; } @@ -693,23 +699,23 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, struct ip6_tnl *t; struct ipv6hdr *ipv6h = ipv6_hdr(skb); - read_lock(&ip6_tnl_lock); + rcu_read_lock(); if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr)) != NULL) { if (t->parms.proto != ipproto && t->parms.proto != 0) { - read_unlock(&ip6_tnl_lock); + rcu_read_unlock(); goto discard; } if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - read_unlock(&ip6_tnl_lock); + rcu_read_unlock(); goto discard; } if (!ip6_tnl_rcv_ctl(t)) { t->dev->stats.rx_dropped++; - read_unlock(&ip6_tnl_lock); + rcu_read_unlock(); goto discard; } secpath_reset(skb); @@ -727,10 +733,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, t->dev->stats.rx_packets++; t->dev->stats.rx_bytes += skb->len; netif_rx(skb); - read_unlock(&ip6_tnl_lock); + rcu_read_unlock(); return 0; } - read_unlock(&ip6_tnl_lock); + rcu_read_unlock(); return 1; discard: -- cgit v1.2.3 From 8d5b2c084d2e71587e30a6ef528a8a8051e59dcd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 23 Oct 2009 06:14:38 +0000 Subject: gre: convert hash tables locking to RCU GRE tunnels use one rwlock to protect their hash tables. This locking scheme can be converted to RCU for free, since netdevice already must wait for a RCU grace period at dismantle time. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 89ff9d5b150..40f04391523 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -156,8 +156,13 @@ struct ipgre_net { #define tunnels_r tunnels[2] #define tunnels_l tunnels[1] #define tunnels_wc tunnels[0] +/* + * Locking : hash tables are protected by RCU and a spinlock + */ +static DEFINE_SPINLOCK(ipgre_lock); -static DEFINE_RWLOCK(ipgre_lock); +#define for_each_ip_tunnel_rcu(start) \ + for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) /* Given src, dst and key, find appropriate for input tunnel. */ @@ -175,7 +180,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, ARPHRD_ETHER : ARPHRD_IPGRE; int score, cand_score = 4; - for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) { + for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) { if (local != t->parms.iph.saddr || remote != t->parms.iph.daddr || key != t->parms.i_key || @@ -200,7 +205,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, } } - for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { + for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) { if (remote != t->parms.iph.daddr || key != t->parms.i_key || !(t->dev->flags & IFF_UP)) @@ -224,7 +229,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, } } - for (t = ign->tunnels_l[h1]; t; t = t->next) { + for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) { if ((local != t->parms.iph.saddr && (local != t->parms.iph.daddr || !ipv4_is_multicast(local))) || @@ -250,7 +255,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, } } - for (t = ign->tunnels_wc[h1]; t; t = t->next) { + for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) { if (t->parms.i_key != key || !(t->dev->flags & IFF_UP)) continue; @@ -276,8 +281,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev, if (cand != NULL) return cand; - if (ign->fb_tunnel_dev->flags & IFF_UP) - return netdev_priv(ign->fb_tunnel_dev); + dev = ign->fb_tunnel_dev; + if (dev->flags & IFF_UP) + return netdev_priv(dev); return NULL; } @@ -311,10 +317,10 @@ static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t) { struct ip_tunnel **tp = ipgre_bucket(ign, t); + spin_lock_bh(&ipgre_lock); t->next = *tp; - write_lock_bh(&ipgre_lock); - *tp = t; - write_unlock_bh(&ipgre_lock); + rcu_assign_pointer(*tp, t); + spin_unlock_bh(&ipgre_lock); } static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t) @@ -323,9 +329,9 @@ static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t) for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) { if (t == *tp) { - write_lock_bh(&ipgre_lock); + spin_lock_bh(&ipgre_lock); *tp = t->next; - write_unlock_bh(&ipgre_lock); + spin_unlock_bh(&ipgre_lock); break; } } @@ -476,7 +482,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) break; } - read_lock(&ipgre_lock); + rcu_read_lock(); t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, flags & GRE_KEY ? *(((__be32 *)p) + (grehlen / 4) - 1) : 0, @@ -494,7 +500,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) t->err_count = 1; t->err_time = jiffies; out: - read_unlock(&ipgre_lock); + rcu_read_unlock(); return; } @@ -573,7 +579,7 @@ static int ipgre_rcv(struct sk_buff *skb) gre_proto = *(__be16 *)(h + 2); - read_lock(&ipgre_lock); + rcu_read_lock(); if ((tunnel = ipgre_tunnel_lookup(skb->dev, iph->saddr, iph->daddr, key, gre_proto))) { @@ -647,13 +653,13 @@ static int ipgre_rcv(struct sk_buff *skb) ipgre_ecn_decapsulate(iph, skb); netif_rx(skb); - read_unlock(&ipgre_lock); + rcu_read_unlock(); return(0); } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); drop: - read_unlock(&ipgre_lock); + rcu_read_unlock(); drop_nolock: kfree_skb(skb); return(0); -- cgit v1.2.3 From 7c28bd0b8ec4d128bd7660671d1b626b0abc471f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 24 Oct 2009 06:13:17 -0700 Subject: rtnetlink: speedup rtnl_dump_ifinfo() When handling large number of netdevice, rtnl_dump_ifinfo() is very slow because it has O(N^2) complexity. Instead of scanning one single list, we can use the 256 sub lists of the dev_index hash table. This considerably speedups "ip link" operations Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/net_namespace.h | 4 ++++ net/core/dev.c | 7 ++----- net/core/rtnetlink.c | 37 ++++++++++++++++++++++++------------- 3 files changed, 30 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 699410142bf..0addd45038a 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -28,6 +28,10 @@ struct ctl_table_header; struct net_generic; struct sock; + +#define NETDEV_HASHBITS 8 +#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) + struct net { atomic_t count; /* To decided when the network * namespace should be freed. diff --git a/net/core/dev.c b/net/core/dev.c index fa88dcd476d..e7bada1d5ed 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -193,18 +193,15 @@ static struct list_head ptype_all __read_mostly; /* Taps */ DEFINE_RWLOCK(dev_base_lock); EXPORT_SYMBOL(dev_base_lock); -#define NETDEV_HASHBITS 8 -#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) - static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) { unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); - return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)]; + return &net->dev_name_head[hash & (NETDEV_HASHENTRIES - 1)]; } static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) { - return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; + return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)]; } /* Device list insertion */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index ba13b0974a7..52ea418d530 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -682,22 +682,33 @@ nla_put_failure: static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); - int idx; - int s_idx = cb->args[0]; + int h, s_h; + int idx = 0, s_idx; struct net_device *dev; - - idx = 0; - for_each_netdev(net, dev) { - if (idx < s_idx) - goto cont; - if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0) - break; + struct hlist_head *head; + struct hlist_node *node; + + s_h = cb->args[0]; + s_idx = cb->args[1]; + + for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { + idx = 0; + head = &net->dev_index_head[h]; + hlist_for_each_entry(dev, node, head, index_hlist) { + if (idx < s_idx) + goto cont; + if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, 0, + NLM_F_MULTI) <= 0) + goto out; cont: - idx++; + idx++; + } } - cb->args[0] = idx; +out: + cb->args[1] = idx; + cb->args[0] = h; return skb->len; } -- cgit v1.2.3 From 05423b241311c9380b7280179295bac7794281b6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 26 Oct 2009 18:40:35 -0700 Subject: vlan: allow null VLAN ID to be used We currently use a 16 bit field (vlan_tci) to store VLAN ID/PRIO on a skb. Null value is used as a special value, meaning vlan tagging not enabled. This forbids use of null vlan ID. As pointed by David, some drivers use the 3 high order bits (PRIO) As VLAN ID is 12 bits, we can use the remaining bit (CFI) as a flag, and allow null VLAN ID. In case future code really wants to use VLAN_CFI_MASK, we'll have to use a bit outside of vlan_tci. #define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ #define VLAN_PRIO_SHIFT 13 #define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ #define VLAN_TAG_PRESENT VLAN_CFI_MASK #define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ Reported-by: Gertjan Hofman Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 14 +++++++++----- net/8021q/vlan.h | 2 +- net/8021q/vlan_dev.c | 2 +- net/core/dev.c | 2 +- net/packet/af_packet.c | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 7ff9af1d0f0..8898cbebcf3 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -63,7 +63,11 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb) return (struct vlan_ethhdr *)skb_mac_header(skb); } -#define VLAN_VID_MASK 0xfff +#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ +#define VLAN_PRIO_SHIFT 13 +#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ +#define VLAN_TAG_PRESENT VLAN_CFI_MASK +#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ /* found in socket.c */ extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); @@ -105,8 +109,8 @@ static inline void vlan_group_set_device(struct vlan_group *vg, array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; } -#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci) -#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci) +#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT) +#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); @@ -231,7 +235,7 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci) { - skb->vlan_tci = vlan_tci; + skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci; return skb; } @@ -284,7 +288,7 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb, u16 *vlan_tci) { if (vlan_tx_tag_present(skb)) { - *vlan_tci = skb->vlan_tci; + *vlan_tci = vlan_tx_tag_get(skb); return 0; } else { *vlan_tci = 0; diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 82570bc2a18..4ade5edf103 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -89,7 +89,7 @@ static inline u32 vlan_get_ingress_priority(struct net_device *dev, { struct vlan_dev_info *vip = vlan_dev_info(dev); - return vip->ingress_priority_map[(vlan_tci >> 13) & 0x7]; + return vip->ingress_priority_map[(vlan_tci >> VLAN_PRIO_SHIFT) & 0x7]; } #ifdef CONFIG_VLAN_8021Q_GVRP diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 4198ec5c8ab..e3701977f58 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -393,7 +393,7 @@ int vlan_dev_set_egress_priority(const struct net_device *dev, struct vlan_dev_info *vlan = vlan_dev_info(dev); struct vlan_priority_tci_mapping *mp = NULL; struct vlan_priority_tci_mapping *np; - u32 vlan_qos = (vlan_prio << 13) & 0xE000; + u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK; /* See if a priority mapping exists.. */ mp = vlan->egress_priority_map[skb_prio & 0xF]; diff --git a/net/core/dev.c b/net/core/dev.c index e7bada1d5ed..950c13fa60d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2300,7 +2300,7 @@ int netif_receive_skb(struct sk_buff *skb) if (!skb->tstamp.tv64) net_timestamp(skb); - if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) + if (vlan_tx_tag_present(skb) && vlan_hwaccel_do_receive(skb)) return NET_RX_SUCCESS; /* if we've gotten here through NAPI, check netpoll */ diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ff752c60641..33e68f20ec6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -79,6 +79,7 @@ #include #include #include +#include #ifdef CONFIG_INET #include @@ -766,7 +767,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, getnstimeofday(&ts); h.h2->tp_sec = ts.tv_sec; h.h2->tp_nsec = ts.tv_nsec; - h.h2->tp_vlan_tci = skb->vlan_tci; + h.h2->tp_vlan_tci = vlan_tx_tag_get(skb); hdrlen = sizeof(*h.h2); break; default: @@ -1493,7 +1494,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, aux.tp_snaplen = skb->len; aux.tp_mac = 0; aux.tp_net = skb_network_offset(skb); - aux.tp_vlan_tci = skb->vlan_tci; + aux.tp_vlan_tci = vlan_tx_tag_get(skb); put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); } -- cgit v1.2.3 From ce470613cdfde70f25419cc52a4816315825f5d9 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 13 Oct 2009 13:28:13 +0200 Subject: cfg80211: no cookies in cfg80211_send_XXX() Get rid of cookies in cfg80211_send_XXX() functions. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- include/net/cfg80211.h | 31 +++++++++++++++++++++++-------- net/mac80211/mlme.c | 18 +++++++++++------- net/wireless/mlme.c | 39 ++++++++++++--------------------------- 3 files changed, 46 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6f4862b3ec2..ff67865de23 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1809,30 +1809,45 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); * @dev: network device * @buf: deauthentication frame (header + body) * @len: length of the frame data - * @cookie: cookie from ->deauth if called within that callback, - * %NULL otherwise * * This function is called whenever deauthentication has been processed in * station mode. This includes both received deauthentication frames and * locally generated ones. This function may sleep. */ -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, - void *cookie); +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); + +/** + * __cfg80211_send_deauth - notification of processed deauthentication + * @dev: network device + * @buf: deauthentication frame (header + body) + * @len: length of the frame data + * + * Like cfg80211_send_deauth(), but doesn't take the wdev lock. + */ +void __cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); /** * cfg80211_send_disassoc - notification of processed disassociation * @dev: network device * @buf: disassociation response frame (header + body) * @len: length of the frame data - * @cookie: cookie from ->disassoc if called within that callback, - * %NULL otherwise * * This function is called whenever disassociation has been processed in * station mode. This includes both received disassociation frames and locally * generated ones. This function may sleep. */ -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, - void *cookie); +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); + +/** + * __cfg80211_send_disassoc - notification of processed disassociation + * @dev: network device + * @buf: disassociation response frame (header + body) + * @len: length of the frame data + * + * Like cfg80211_send_disassoc(), but doesn't take the wdev lock. + */ +void __cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, + size_t len); /** * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8d26e9bf896..33a696f5f30 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -458,9 +458,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie); + if (cookie) + __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + else + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); else - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie); + if (cookie) + __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); + else + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1959,12 +1965,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, - NULL); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); break; case RX_MGMT_CFG80211_DISASSOC: - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, - NULL); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); @@ -2019,7 +2023,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index ceb2c14c8f4..a13a7120524 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -121,7 +121,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) } EXPORT_SYMBOL(cfg80211_send_rx_assoc); -static void __cfg80211_send_deauth(struct net_device *dev, +void __cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -177,27 +177,19 @@ static void __cfg80211_send_deauth(struct net_device *dev, false, NULL); } } +EXPORT_SYMBOL(__cfg80211_send_deauth); - -void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, - void *cookie) +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; - BUG_ON(cookie && wdev != cookie); - - if (cookie) { - /* called within callback */ - __cfg80211_send_deauth(dev, buf, len); - } else { - wdev_lock(wdev); - __cfg80211_send_deauth(dev, buf, len); - wdev_unlock(wdev); - } + wdev_lock(wdev); + __cfg80211_send_deauth(dev, buf, len); + wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_deauth); -static void __cfg80211_send_disassoc(struct net_device *dev, +void __cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -238,22 +230,15 @@ static void __cfg80211_send_disassoc(struct net_device *dev, from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); } +EXPORT_SYMBOL(__cfg80211_send_disassoc); -void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, - void *cookie) +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) { struct wireless_dev *wdev = dev->ieee80211_ptr; - BUG_ON(cookie && wdev != cookie); - - if (cookie) { - /* called within callback */ - __cfg80211_send_disassoc(dev, buf, len); - } else { - wdev_lock(wdev); - __cfg80211_send_disassoc(dev, buf, len); - wdev_unlock(wdev); - } + wdev_lock(wdev); + __cfg80211_send_disassoc(dev, buf, len); + wdev_unlock(wdev); } EXPORT_SYMBOL(cfg80211_send_disassoc); -- cgit v1.2.3 From e0da41b2cf10ae95592cb2496f8f81aa4b4bf16c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 13 Oct 2009 13:45:28 +0200 Subject: cfg80211: remove warning in deauth case It might be the case that __cfg80211_disconnected() has already cleaned up wdev->current_bss() for us. The old code didn't catch that situation and didn't warn needlessly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- net/wireless/mlme.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'net') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index a13a7120524..1f87b4e7f4f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -130,7 +130,6 @@ void __cfg80211_send_deauth(struct net_device *dev, struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; int i; - bool done = false; ASSERT_WDEV_LOCK(wdev); @@ -138,7 +137,6 @@ void __cfg80211_send_deauth(struct net_device *dev, if (wdev->current_bss && memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { - done = true; cfg80211_unhold_bss(wdev->current_bss); cfg80211_put_bss(&wdev->current_bss->pub); wdev->current_bss = NULL; @@ -148,7 +146,6 @@ void __cfg80211_send_deauth(struct net_device *dev, cfg80211_unhold_bss(wdev->auth_bsses[i]); cfg80211_put_bss(&wdev->auth_bsses[i]->pub); wdev->auth_bsses[i] = NULL; - done = true; break; } if (wdev->authtry_bsses[i] && @@ -156,13 +153,10 @@ void __cfg80211_send_deauth(struct net_device *dev, cfg80211_unhold_bss(wdev->authtry_bsses[i]); cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); wdev->authtry_bsses[i] = NULL; - done = true; break; } } - WARN_ON(!done); - if (wdev->sme_state == CFG80211_SME_CONNECTED) { u16 reason_code; bool from_ap; -- cgit v1.2.3 From 53623f1a09c7a7d23b74f0f7d93dba0ebde1006b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 15 Oct 2009 15:10:16 -0400 Subject: mac80211: replace netif_tx_{start,stop,wake}_all_queues Replace netif_tx_{start,stop,wake}_all_queues with the single-queue equivalents (i.e. netif_{start,stop,wake}_queue). Since we are down to a single queue, these should peform slightly better. Signed-off-by: John W. Linville --- net/mac80211/iface.c | 4 ++-- net/mac80211/mlme.c | 4 ++-- net/mac80211/scan.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 87aff1d923b..14f10eb91c5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -314,7 +314,7 @@ static int ieee80211_open(struct net_device *dev) if (sdata->vif.type == NL80211_IFTYPE_STATION) ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); - netif_tx_start_all_queues(dev); + netif_start_queue(dev); return 0; err_del_interface: @@ -343,7 +343,7 @@ static int ieee80211_stop(struct net_device *dev) /* * Stop TX on this interface first. */ - netif_tx_stop_all_queues(dev); + netif_stop_queue(dev); /* * Now delete all active aggregation sessions. diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 33a696f5f30..71220a5d140 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -929,7 +929,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_ps(local, -1); mutex_unlock(&local->iflist_mtx); - netif_tx_start_all_queues(sdata->dev); + netif_start_queue(sdata->dev); netif_carrier_on(sdata->dev); } @@ -1061,7 +1061,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, * time -- we don't want the scan code to enable queues. */ - netif_tx_stop_all_queues(sdata->dev); + netif_stop_queue(sdata->dev); netif_carrier_off(sdata->dev); rcu_read_lock(); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 71e10cabf81..7a350d2690a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -306,10 +306,10 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.associated) { ieee80211_scan_ps_disable(sdata); - netif_tx_wake_all_queues(sdata->dev); + netif_wake_queue(sdata->dev); } } else - netif_tx_wake_all_queues(sdata->dev); + netif_wake_queue(sdata->dev); /* re-enable beaconing */ if (sdata->vif.type == NL80211_IFTYPE_AP || @@ -364,7 +364,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) * are handled in the scan state machine */ if (sdata->vif.type != NL80211_IFTYPE_STATION) - netif_tx_stop_all_queues(sdata->dev); + netif_stop_queue(sdata->dev); } mutex_unlock(&local->iflist_mtx); @@ -523,7 +523,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca continue; if (sdata->vif.type == NL80211_IFTYPE_STATION) { - netif_tx_stop_all_queues(sdata->dev); + netif_stop_queue(sdata->dev); if (sdata->u.mgd.associated) ieee80211_scan_ps_enable(sdata); } @@ -558,7 +558,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.associated) ieee80211_scan_ps_disable(sdata); - netif_tx_wake_all_queues(sdata->dev); + netif_wake_queue(sdata->dev); } } mutex_unlock(&local->iflist_mtx); -- cgit v1.2.3 From 43b7b314f606b64f8645e4ec1a59df8a97a79b5a Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 15 Oct 2009 18:10:51 -0700 Subject: mac80211: Learn about mesh portals from multicast traffic Mesh portals proxy traffic for nodes external to the mesh. When a proxied frame is received by a mesh interface, it should update its mesh portal table. This was only happening for unicast frames. With this change we also learn about mesh portals from proxied multicast frames. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/rx.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7170bf4565a..5c385e3c1d1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1504,19 +1504,28 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* illegal frame */ return RX_DROP_MONITOR; - if (!is_multicast_ether_addr(hdr->addr1) && - (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) { + if (mesh_hdr->flags & MESH_FLAGS_AE) { struct mesh_path *mppath; + char *proxied_addr; + char *mpp_addr; + + if (is_multicast_ether_addr(hdr->addr1)) { + mpp_addr = hdr->addr3; + proxied_addr = mesh_hdr->eaddr1; + } else { + mpp_addr = hdr->addr4; + proxied_addr = mesh_hdr->eaddr2; + } rcu_read_lock(); - mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata); + mppath = mpp_path_lookup(proxied_addr, sdata); if (!mppath) { - mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata); + mpp_path_add(proxied_addr, mpp_addr, sdata); } else { spin_lock_bh(&mppath->state_lock); mppath->exp_time = jiffies; - if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0) - memcpy(mppath->mpp, hdr->addr4, ETH_ALEN); + if (compare_ether_addr(mppath->mpp, mpp_addr) != 0) + memcpy(mppath->mpp, mpp_addr, ETH_ALEN); spin_unlock_bh(&mppath->state_lock); } rcu_read_unlock(); -- cgit v1.2.3 From 6b9ac4425d6ec871faf54540e0f1c5ff420a8f29 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Tue, 20 Oct 2009 21:21:48 +0100 Subject: mesh: use set_bit() to set MESH_WORK_HOUSEKEEPING. This makes the mesh housekeeping timer work properly on big endian systems. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f7364e56f1e..9a733890eb4 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -50,7 +50,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; + set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); if (local->quiescing) { set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); @@ -480,7 +480,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; - ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; + set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); ieee80211_queue_work(&local->hw, &ifmsh->work); sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | -- cgit v1.2.3 From 44a0873d52282f24b1894c58c0f157e0f626ddc9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Oct 2009 07:03:04 +0000 Subject: net: Introduce unregister_netdevice_queue() This patchs adds an unreg_list anchor to struct net_device, and introduces an unregister_netdevice_queue() function, able to queue a net_device to a list instead of immediately unregister it. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 9 ++++++++- net/core/dev.c | 20 +++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 83800091a31..0ded0a4768a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -683,6 +683,7 @@ struct net_device struct list_head dev_list; struct list_head napi_list; + struct list_head unreg_list; /* Net device features */ unsigned long features; @@ -1116,7 +1117,13 @@ extern int dev_close(struct net_device *dev); extern void dev_disable_lro(struct net_device *dev); extern int dev_queue_xmit(struct sk_buff *skb); extern int register_netdevice(struct net_device *dev); -extern void unregister_netdevice(struct net_device *dev); +extern void unregister_netdevice_queue(struct net_device *dev, + struct list_head *head); +static inline void unregister_netdevice(struct net_device *dev) +{ + unregister_netdevice_queue(dev, NULL); +} + extern void free_netdev(struct net_device *dev); extern void synchronize_net(void); extern int register_netdevice_notifier(struct notifier_block *nb); diff --git a/net/core/dev.c b/net/core/dev.c index 950c13fa60d..ff94e2b8df7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5245,25 +5245,31 @@ void synchronize_net(void) EXPORT_SYMBOL(synchronize_net); /** - * unregister_netdevice - remove device from the kernel + * unregister_netdevice_queue - remove device from the kernel * @dev: device - * + * @head: list + * This function shuts down a device interface and removes it * from the kernel tables. + * If head not NULL, device is queued to be unregistered later. * * Callers must hold the rtnl semaphore. You may want * unregister_netdev() instead of this. */ -void unregister_netdevice(struct net_device *dev) +void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) { ASSERT_RTNL(); - rollback_registered(dev); - /* Finish processing unregister after unlock */ - net_set_todo(dev); + if (head) { + list_add_tail(&dev->unreg_list, head); + } else { + rollback_registered(dev); + /* Finish processing unregister after unlock */ + net_set_todo(dev); + } } -EXPORT_SYMBOL(unregister_netdevice); +EXPORT_SYMBOL(unregister_netdevice_queue); /** * unregister_netdev - remove device from the kernel -- cgit v1.2.3 From 9b5e383c11b08784eb0087617f880077982ef769 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Oct 2009 07:04:19 +0000 Subject: net: Introduce unregister_netdevice_many() Introduce rollback_registered_many() and unregister_netdevice_many() rollback_registered_many() is able to perform necessary steps at device dismantle time, factorizing two expensive synchronize_net() calls. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + net/core/dev.c | 97 +++++++++++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0ded0a4768a..e7c227d7cb9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1119,6 +1119,7 @@ extern int dev_queue_xmit(struct sk_buff *skb); extern int register_netdevice(struct net_device *dev); extern void unregister_netdevice_queue(struct net_device *dev, struct list_head *head); +extern void unregister_netdevice_many(struct list_head *head); static inline void unregister_netdevice(struct net_device *dev) { unregister_netdevice_queue(dev, NULL); diff --git a/net/core/dev.c b/net/core/dev.c index ff94e2b8df7..04d3e301402 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4637,59 +4637,76 @@ static void net_set_todo(struct net_device *dev) list_add_tail(&dev->todo_list, &net_todo_list); } -static void rollback_registered(struct net_device *dev) +static void rollback_registered_many(struct list_head *head) { + struct net_device *dev; + BUG_ON(dev_boot_phase); ASSERT_RTNL(); - /* Some devices call without registering for initialization unwind. */ - if (dev->reg_state == NETREG_UNINITIALIZED) { - printk(KERN_DEBUG "unregister_netdevice: device %s/%p never " - "was registered\n", dev->name, dev); + list_for_each_entry(dev, head, unreg_list) { + /* Some devices call without registering + * for initialization unwind. + */ + if (dev->reg_state == NETREG_UNINITIALIZED) { + pr_debug("unregister_netdevice: device %s/%p never " + "was registered\n", dev->name, dev); - WARN_ON(1); - return; - } + WARN_ON(1); + return; + } - BUG_ON(dev->reg_state != NETREG_REGISTERED); + BUG_ON(dev->reg_state != NETREG_REGISTERED); - /* If device is running, close it first. */ - dev_close(dev); + /* If device is running, close it first. */ + dev_close(dev); - /* And unlink it from device chain. */ - unlist_netdevice(dev); + /* And unlink it from device chain. */ + unlist_netdevice(dev); - dev->reg_state = NETREG_UNREGISTERING; + dev->reg_state = NETREG_UNREGISTERING; + } synchronize_net(); - /* Shutdown queueing discipline. */ - dev_shutdown(dev); + list_for_each_entry(dev, head, unreg_list) { + /* Shutdown queueing discipline. */ + dev_shutdown(dev); - /* Notify protocols, that we are about to destroy - this device. They should clean all the things. - */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); + /* Notify protocols, that we are about to destroy + this device. They should clean all the things. + */ + call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - /* - * Flush the unicast and multicast chains - */ - dev_unicast_flush(dev); - dev_addr_discard(dev); + /* + * Flush the unicast and multicast chains + */ + dev_unicast_flush(dev); + dev_addr_discard(dev); - if (dev->netdev_ops->ndo_uninit) - dev->netdev_ops->ndo_uninit(dev); + if (dev->netdev_ops->ndo_uninit) + dev->netdev_ops->ndo_uninit(dev); - /* Notifier chain MUST detach us from master device. */ - WARN_ON(dev->master); + /* Notifier chain MUST detach us from master device. */ + WARN_ON(dev->master); - /* Remove entries from kobject tree */ - netdev_unregister_kobject(dev); + /* Remove entries from kobject tree */ + netdev_unregister_kobject(dev); + } synchronize_net(); - dev_put(dev); + list_for_each_entry(dev, head, unreg_list) + dev_put(dev); +} + +static void rollback_registered(struct net_device *dev) +{ + LIST_HEAD(single); + + list_add(&dev->unreg_list, &single); + rollback_registered_many(&single); } static void __netdev_init_queue_locks_one(struct net_device *dev, @@ -5271,6 +5288,22 @@ void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) } EXPORT_SYMBOL(unregister_netdevice_queue); +/** + * unregister_netdevice_many - unregister many devices + * @head: list of devices + * + */ +void unregister_netdevice_many(struct list_head *head) +{ + struct net_device *dev; + + if (!list_empty(head)) { + rollback_registered_many(head); + list_for_each_entry(dev, head, unreg_list) + net_set_todo(dev); + } +} + /** * unregister_netdev - remove device from the kernel * @dev: device -- cgit v1.2.3 From 23289a37e2b127dfc4de1313fba15bb4c9f0cd5b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Oct 2009 07:06:36 +0000 Subject: net: add a list_head parameter to dellink() method Adding a list_head parameter to rtnl_link_ops->dellink() methods allow us to queue devices on a list, in order to dismantle them all at once. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 6 +++--- drivers/net/veth.c | 2 +- include/net/rtnetlink.h | 3 ++- net/8021q/vlan.c | 8 ++++---- net/8021q/vlan.h | 2 +- net/core/dev.c | 2 +- net/core/rtnetlink.c | 14 +++++++------- 7 files changed, 19 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 3aabfd9dd21..20b7707f38e 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -555,13 +555,13 @@ static int macvlan_newlink(struct net_device *dev, return 0; } -static void macvlan_dellink(struct net_device *dev) +static void macvlan_dellink(struct net_device *dev, struct list_head *head) { struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_port *port = vlan->port; list_del(&vlan->list); - unregister_netdevice(dev); + unregister_netdevice_queue(dev, head); if (list_empty(&port->vlans)) macvlan_port_destroy(port->dev); @@ -601,7 +601,7 @@ static int macvlan_device_event(struct notifier_block *unused, break; case NETDEV_UNREGISTER: list_for_each_entry_safe(vlan, next, &port->vlans, list) - macvlan_dellink(vlan->dev); + macvlan_dellink(vlan->dev, NULL); break; } return NOTIFY_DONE; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index ade5b344f75..ffb502daa91 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -442,7 +442,7 @@ err_register_peer: return err; } -static void veth_dellink(struct net_device *dev) +static void veth_dellink(struct net_device *dev, struct list_head *head) { struct veth_priv *priv; struct net_device *peer; diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index c3aa044d3fc..cd5af1f508f 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -61,7 +61,8 @@ struct rtnl_link_ops { int (*changelink)(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]); - void (*dellink)(struct net_device *dev); + void (*dellink)(struct net_device *dev, + struct list_head *head); size_t (*get_size)(const struct net_device *dev); int (*fill_info)(struct sk_buff *skb, diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 8836575f9d7..6b5c9dddaa7 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -140,7 +140,7 @@ static void vlan_rcu_free(struct rcu_head *rcu) vlan_group_free(container_of(rcu, struct vlan_group, rcu)); } -void unregister_vlan_dev(struct net_device *dev) +void unregister_vlan_dev(struct net_device *dev, struct list_head *head) { struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; @@ -164,7 +164,7 @@ void unregister_vlan_dev(struct net_device *dev) synchronize_net(); - unregister_netdevice(dev); + unregister_netdevice_queue(dev, head); /* If the group is now empty, kill off the group. */ if (grp->nr_vlans == 0) { @@ -535,7 +535,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, if (grp->nr_vlans == 1) i = VLAN_GROUP_ARRAY_LEN; - unregister_vlan_dev(vlandev); + unregister_vlan_dev(vlandev, NULL); } break; } @@ -642,7 +642,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; - unregister_vlan_dev(dev); + unregister_vlan_dev(dev, NULL); err = 0; break; diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 4ade5edf103..68f9290e683 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -82,7 +82,7 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result); int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id); void vlan_setup(struct net_device *dev); int register_vlan_dev(struct net_device *dev); -void unregister_vlan_dev(struct net_device *dev); +void unregister_vlan_dev(struct net_device *dev, struct list_head *head); static inline u32 vlan_get_ingress_priority(struct net_device *dev, u16 vlan_tci) diff --git a/net/core/dev.c b/net/core/dev.c index 04d3e301402..4513dfd5718 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5629,7 +5629,7 @@ restart: /* Delete virtual devices */ if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) { - dev->rtnl_link_ops->dellink(dev); + dev->rtnl_link_ops->dellink(dev, NULL); goto restart; } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 52ea418d530..391a62cd9df 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -248,7 +248,7 @@ static LIST_HEAD(link_ops); int __rtnl_link_register(struct rtnl_link_ops *ops) { if (!ops->dellink) - ops->dellink = unregister_netdevice; + ops->dellink = unregister_netdevice_queue; list_add_tail(&ops->list, &link_ops); return 0; @@ -277,13 +277,13 @@ EXPORT_SYMBOL_GPL(rtnl_link_register); static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) { struct net_device *dev; -restart: + LIST_HEAD(list_kill); + for_each_netdev(net, dev) { - if (dev->rtnl_link_ops == ops) { - ops->dellink(dev); - goto restart; - } + if (dev->rtnl_link_ops == ops) + ops->dellink(dev, &list_kill); } + unregister_netdevice_many(&list_kill); } void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) @@ -972,7 +972,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) if (!ops) return -EOPNOTSUPP; - ops->dellink(dev); + ops->dellink(dev, NULL); return 0; } -- cgit v1.2.3 From 63c8099d90096db56ee1c66c31f05d4fcfbc1c69 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Oct 2009 07:06:49 +0000 Subject: vlan: Optimize multiple unregistration Use unregister_netdevice_many() to speedup master device unregister. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 1 + net/8021q/vlan.c | 49 +++++++++++++++++++++++++++++++++---------------- net/core/dev.c | 1 + 3 files changed, 35 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 8898cbebcf3..71a4870c09a 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -85,6 +85,7 @@ struct vlan_group { * the vlan is attached to. */ unsigned int nr_vlans; + int killall; struct hlist_node hlist; /* linked list */ struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; struct rcu_head rcu; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 6b5c9dddaa7..511afe72af3 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -159,11 +159,12 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) if (real_dev->features & NETIF_F_HW_VLAN_FILTER) ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); - vlan_group_set_device(grp, vlan_id, NULL); grp->nr_vlans--; - synchronize_net(); - + if (!grp->killall) { + vlan_group_set_device(grp, vlan_id, NULL); + synchronize_net(); + } unregister_netdevice_queue(dev, head); /* If the group is now empty, kill off the group. */ @@ -183,6 +184,34 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) dev_put(real_dev); } +void unregister_vlan_dev_alls(struct vlan_group *grp) +{ + LIST_HEAD(list); + int i; + struct net_device *vlandev; + struct vlan_group save; + + memcpy(&save, grp, sizeof(save)); + memset(&grp->vlan_devices_arrays, 0, sizeof(grp->vlan_devices_arrays)); + grp->killall = 1; + + synchronize_net(); + + /* Delete all VLANs for this dev. */ + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + vlandev = vlan_group_get_device(&save, i); + if (!vlandev) + continue; + + unregister_vlan_dev(vlandev, &list); + if (grp->nr_vlans == 0) + break; + } + unregister_netdevice_many(&list); + for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) + kfree(save.vlan_devices_arrays[i]); +} + static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) { @@ -524,19 +553,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, break; case NETDEV_UNREGISTER: - /* Delete all VLANs for this dev. */ - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - vlandev = vlan_group_get_device(grp, i); - if (!vlandev) - continue; - - /* unregistration of last vlan destroys group, abort - * afterwards */ - if (grp->nr_vlans == 1) - i = VLAN_GROUP_ARRAY_LEN; - - unregister_vlan_dev(vlandev, NULL); - } + unregister_vlan_dev_alls(grp); break; } diff --git a/net/core/dev.c b/net/core/dev.c index 4513dfd5718..09551cc143a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5303,6 +5303,7 @@ void unregister_netdevice_many(struct list_head *head) net_set_todo(dev); } } +EXPORT_SYMBOL(unregister_netdevice_many); /** * unregister_netdev - remove device from the kernel -- cgit v1.2.3 From 0694c4c016df34c718b9f9ef6ba5aca2e178163a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Oct 2009 07:06:59 +0000 Subject: ipip: Optimize multiple unregistration Speedup module unloading by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 3bd69988bcc..a2ca53da437 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -754,16 +754,19 @@ static struct xfrm_tunnel ipip_handler = { static const char banner[] __initconst = KERN_INFO "IPv4 over IPv4 tunneling driver\n"; -static void ipip_destroy_tunnels(struct ipip_net *ipn) +static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head) { int prio; for (prio = 1; prio < 4; prio++) { int h; for (h = 0; h < HASH_SIZE; h++) { - struct ip_tunnel *t; - while ((t = ipn->tunnels[prio][h]) != NULL) - unregister_netdevice(t->dev); + struct ip_tunnel *t = ipn->tunnels[prio][h]; + + while (t != NULL) { + unregister_netdevice_queue(t->dev, head); + t = t->next; + } } } } @@ -816,11 +819,13 @@ err_alloc: static void ipip_exit_net(struct net *net) { struct ipip_net *ipn; + LIST_HEAD(list); ipn = net_generic(net, ipip_net_id); rtnl_lock(); - ipip_destroy_tunnels(ipn); - unregister_netdevice(ipn->fb_tunnel_dev); + ipip_destroy_tunnels(ipn, &list); + unregister_netdevice_queue(ipn->fb_tunnel_dev, &list); + unregister_netdevice_many(&list); rtnl_unlock(); kfree(ipn); } -- cgit v1.2.3 From eef6dd65e331d6e91a39b90344c705bbcbe0825e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Oct 2009 07:07:16 +0000 Subject: gre: Optimize multiple unregistration Speedup module unloading by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 40f04391523..a77807d449e 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1290,16 +1290,19 @@ static const struct net_protocol ipgre_protocol = { .netns_ok = 1, }; -static void ipgre_destroy_tunnels(struct ipgre_net *ign) +static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head) { int prio; for (prio = 0; prio < 4; prio++) { int h; for (h = 0; h < HASH_SIZE; h++) { - struct ip_tunnel *t; - while ((t = ign->tunnels[prio][h]) != NULL) - unregister_netdevice(t->dev); + struct ip_tunnel *t = ign->tunnels[prio][h]; + + while (t != NULL) { + unregister_netdevice_queue(t->dev, head); + t = t->next; + } } } } @@ -1347,10 +1350,12 @@ err_alloc: static void ipgre_exit_net(struct net *net) { struct ipgre_net *ign; + LIST_HEAD(list); ign = net_generic(net, ipgre_net_id); rtnl_lock(); - ipgre_destroy_tunnels(ign); + ipgre_destroy_tunnels(ign, &list); + unregister_netdevice_many(&list); rtnl_unlock(); kfree(ign); } -- cgit v1.2.3 From ac5e3af9996fb911d4fdff910a8ac3cb7fc63a94 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 26 Oct 2009 01:23:33 +0000 Subject: net: sysfs: ethtool_ops can be NULL commit d519e17e2d01a0ee9abe083019532061b4438065 (net: export device speed and duplex via sysfs) made the wrong assumption that netdev->ethtool_ops was always set. This makes possible to crash kernel and let rtnl in locked state. modprobe dummy ip link set dummy0 up (udev runs and crash) Signed-off-by: Eric Dumazet Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 753c420060d..89de182353b 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -139,7 +139,9 @@ static ssize_t show_speed(struct device *dev, if (!rtnl_trylock()) return restart_syscall(); - if (netif_running(netdev) && netdev->ethtool_ops->get_settings) { + if (netif_running(netdev) && + netdev->ethtool_ops && + netdev->ethtool_ops->get_settings) { struct ethtool_cmd cmd = { ETHTOOL_GSET }; if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) @@ -158,7 +160,9 @@ static ssize_t show_duplex(struct device *dev, if (!rtnl_trylock()) return restart_syscall(); - if (netif_running(netdev) && netdev->ethtool_ops->get_settings) { + if (netif_running(netdev) && + netdev->ethtool_ops && + netdev->ethtool_ops->get_settings) { struct ethtool_cmd cmd = { ETHTOOL_GSET }; if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) -- cgit v1.2.3 From ea84e5555a56e2013687b19b012bcf959d601128 Mon Sep 17 00:00:00 2001 From: Andreas Petlund Date: Tue, 27 Oct 2009 03:27:21 +0000 Subject: net: Corrected spelling error heurestics->heuristics Corrected a spelling error in a function name. Signed-off-by: Andreas Petlund Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d86784be7ab..a0c3700bae3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2300,7 +2300,7 @@ static inline int tcp_fackets_out(struct tcp_sock *tp) * they differ. Since neither occurs due to loss, TCP should really * ignore them. */ -static inline int tcp_dupack_heurestics(struct tcp_sock *tp) +static inline int tcp_dupack_heuristics(struct tcp_sock *tp) { return tcp_is_fack(tp) ? tp->fackets_out : tp->sacked_out + 1; } @@ -2425,7 +2425,7 @@ static int tcp_time_to_recover(struct sock *sk) return 1; /* Not-A-Trick#2 : Classic rule... */ - if (tcp_dupack_heurestics(tp) > tp->reordering) + if (tcp_dupack_heuristics(tp) > tp->reordering) return 1; /* Trick#3 : when we use RFC2988 timer restart, fast -- cgit v1.2.3 From d6534799410d2b53e5e80b8a90d6a8bab3de30ed Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Wed, 28 Oct 2009 18:25:16 +0000 Subject: vlan: Add support to netdev_ops.ndo_fcoe_get_wwn for VLAN device Implements the netdev_ops.ndo_fcoe_get_wwn for VLAN device. Signed-off-by: Yi Zou Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'net') diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index e3701977f58..790fd55ec31 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -626,6 +626,17 @@ static int vlan_dev_fcoe_disable(struct net_device *dev) rc = ops->ndo_fcoe_disable(real_dev); return rc; } + +static int vlan_dev_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type) +{ + struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; + int rc = -EINVAL; + + if (ops->ndo_fcoe_get_wwn) + rc = ops->ndo_fcoe_get_wwn(real_dev, wwn, type); + return rc; +} #endif static void vlan_dev_change_rx_flags(struct net_device *dev, int change) @@ -791,6 +802,7 @@ static const struct net_device_ops vlan_netdev_ops = { .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, .ndo_fcoe_enable = vlan_dev_fcoe_enable, .ndo_fcoe_disable = vlan_dev_fcoe_disable, + .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, #endif }; @@ -813,6 +825,7 @@ static const struct net_device_ops vlan_netdev_accel_ops = { .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, .ndo_fcoe_enable = vlan_dev_fcoe_enable, .ndo_fcoe_disable = vlan_dev_fcoe_disable, + .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, #endif }; -- cgit v1.2.3 From 8c56ba0530af3d5eee6445dce9dc9296f1f74ed5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Oct 2009 05:35:35 +0000 Subject: bridge: Optimize multiple unregistration Speedup module unloading by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/bridge/br_if.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index b1b3b0fbf41..2117e5ba24c 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -154,7 +154,7 @@ static void del_nbp(struct net_bridge_port *p) } /* called with RTNL */ -static void del_br(struct net_bridge *br) +static void del_br(struct net_bridge *br, struct list_head *head) { struct net_bridge_port *p, *n; @@ -165,7 +165,7 @@ static void del_br(struct net_bridge *br) del_timer_sync(&br->gc_timer); br_sysfs_delbr(br->dev); - unregister_netdevice(br->dev); + unregister_netdevice_queue(br->dev, head); } static struct net_device *new_bridge_dev(struct net *net, const char *name) @@ -323,7 +323,7 @@ int br_del_bridge(struct net *net, const char *name) } else - del_br(netdev_priv(dev)); + del_br(netdev_priv(dev), NULL); rtnl_unlock(); return ret; @@ -462,15 +462,14 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) void br_net_exit(struct net *net) { struct net_device *dev; + LIST_HEAD(list); rtnl_lock(); -restart: - for_each_netdev(net, dev) { - if (dev->priv_flags & IFF_EBRIDGE) { - del_br(netdev_priv(dev)); - goto restart; - } - } + for_each_netdev(net, dev) + if (dev->priv_flags & IFF_EBRIDGE) + del_br(netdev_priv(dev), &list); + + unregister_netdevice_many(&list); rtnl_unlock(); } -- cgit v1.2.3 From cf4432f550a0fe4e08e7cd522568cfbae754582c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Oct 2009 05:16:51 +0000 Subject: ip6tnl: Optimize multiple unregistration Speedup module unloading by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 670c291d256..6c1b5c98e81 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1393,14 +1393,19 @@ static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) { int h; struct ip6_tnl *t; + LIST_HEAD(list); for (h = 0; h < HASH_SIZE; h++) { - while ((t = ip6n->tnls_r_l[h]) != NULL) - unregister_netdevice(t->dev); + t = ip6n->tnls_r_l[h]; + while (t != NULL) { + unregister_netdevice_queue(t->dev, &list); + t = t->next; + } } t = ip6n->tnls_wc[0]; - unregister_netdevice(t->dev); + unregister_netdevice_queue(t->dev, &list); + unregister_netdevice_many(&list); } static int ip6_tnl_init_net(struct net *net) -- cgit v1.2.3 From d17fa6fa81d9be6d2dc69aedfabecf904210cbf4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Oct 2009 05:21:38 +0000 Subject: ipmr: Optimize multiple unregistration Speedup module unloading by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 694974502ea..ef4ee45b928 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -275,7 +275,8 @@ failure: * @notify: Set to 1, if the caller is a notifier_call */ -static int vif_delete(struct net *net, int vifi, int notify) +static int vif_delete(struct net *net, int vifi, int notify, + struct list_head *head) { struct vif_device *v; struct net_device *dev; @@ -319,7 +320,7 @@ static int vif_delete(struct net *net, int vifi, int notify) } if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify) - unregister_netdevice(dev); + unregister_netdevice_queue(dev, head); dev_put(dev); return 0; @@ -870,14 +871,16 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock) static void mroute_clean_tables(struct net *net) { int i; + LIST_HEAD(list); /* * Shut down all active vif entries */ for (i = 0; i < net->ipv4.maxvif; i++) { if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC)) - vif_delete(net, i, 0); + vif_delete(net, i, 0, &list); } + unregister_netdevice_many(&list); /* * Wipe the cache @@ -993,7 +996,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi if (optname == MRT_ADD_VIF) { ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk); } else { - ret = vif_delete(net, vif.vifc_vifi, 0); + ret = vif_delete(net, vif.vifc_vifi, 0, NULL); } rtnl_unlock(); return ret; @@ -1156,6 +1159,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v struct net *net = dev_net(dev); struct vif_device *v; int ct; + LIST_HEAD(list); if (!net_eq(dev_net(dev), net)) return NOTIFY_DONE; @@ -1165,8 +1169,9 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v v = &net->ipv4.vif_table[0]; for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) { if (v->dev == dev) - vif_delete(net, ct, 1); + vif_delete(net, ct, 1, &list); } + unregister_netdevice_many(&list); return NOTIFY_DONE; } -- cgit v1.2.3 From 62808f91237181dbac74c2b5be4fa92adfbbbe40 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Oct 2009 04:37:43 +0000 Subject: ipv6 sit: Optimize multiple unregistration Speedup module unloading by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/sit.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index b6b16264b30..2362a3397e9 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1145,16 +1145,19 @@ static struct xfrm_tunnel sit_handler = { .priority = 1, }; -static void sit_destroy_tunnels(struct sit_net *sitn) +static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) { int prio; for (prio = 1; prio < 4; prio++) { int h; for (h = 0; h < HASH_SIZE; h++) { - struct ip_tunnel *t; - while ((t = sitn->tunnels[prio][h]) != NULL) - unregister_netdevice(t->dev); + struct ip_tunnel *t = sitn->tunnels[prio][h]; + + while (t != NULL) { + unregister_netdevice_queue(t->dev, head); + t = t->next; + } } } } @@ -1208,11 +1211,13 @@ err_alloc: static void sit_exit_net(struct net *net) { struct sit_net *sitn; + LIST_HEAD(list); sitn = net_generic(net, sit_net_id); rtnl_lock(); - sit_destroy_tunnels(sitn); - unregister_netdevice(sitn->fb_tunnel_dev); + sit_destroy_tunnels(sitn, &list); + unregister_netdevice_queue(sitn->fb_tunnel_dev, &list); + unregister_netdevice_many(&list); rtnl_unlock(); kfree(sitn); } -- cgit v1.2.3 From c871e664ea39363c2a1011ec2dc4bc172dc396a0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Oct 2009 04:48:11 +0000 Subject: ip6mr: Optimize multiple unregistration Speedup module unloading by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/ip6mr.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 85849b4f5a3..52e0f74fdfe 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -477,7 +477,7 @@ failure: * Delete a VIF entry */ -static int mif6_delete(struct net *net, int vifi) +static int mif6_delete(struct net *net, int vifi, struct list_head *head) { struct mif_device *v; struct net_device *dev; @@ -519,7 +519,7 @@ static int mif6_delete(struct net *net, int vifi) in6_dev->cnf.mc_forwarding--; if (v->flags & MIFF_REGISTER) - unregister_netdevice(dev); + unregister_netdevice_queue(dev, head); dev_put(dev); return 0; @@ -976,6 +976,7 @@ static int ip6mr_device_event(struct notifier_block *this, struct net *net = dev_net(dev); struct mif_device *v; int ct; + LIST_HEAD(list); if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; @@ -983,8 +984,10 @@ static int ip6mr_device_event(struct notifier_block *this, v = &net->ipv6.vif6_table[0]; for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { if (v->dev == dev) - mif6_delete(net, ct); + mif6_delete(net, ct, &list); } + unregister_netdevice_many(&list); + return NOTIFY_DONE; } @@ -1188,14 +1191,16 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) static void mroute_clean_tables(struct net *net) { int i; + LIST_HEAD(list); /* * Shut down all active vif entries */ for (i = 0; i < net->ipv6.maxvif; i++) { if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) - mif6_delete(net, i); + mif6_delete(net, i, &list); } + unregister_netdevice_many(&list); /* * Wipe the cache @@ -1325,7 +1330,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns if (copy_from_user(&mifi, optval, sizeof(mifi_t))) return -EFAULT; rtnl_lock(); - ret = mif6_delete(net, mifi); + ret = mif6_delete(net, mifi, NULL); rtnl_unlock(); return ret; -- cgit v1.2.3 From f55017a93f1a74d50244b1254b9a2bd7ac9bbf7d Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 28 Oct 2009 04:15:21 +0000 Subject: Only parse time stamp TCP option in time wait sock Since we only use tcp_parse_options here to check for the exietence of TCP timestamp option in the header, it is better to call with the "established" flag on. Signed-off-by: Gilad Ben-Yossef Signed-off-by: Ori Finkelman Signed-off-by: Yony Amit Signed-off-by: David S. Miller --- net/ipv4/tcp_minisocks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4c03598ed92..015e7c67dc8 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -100,9 +100,9 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, struct tcp_options_received tmp_opt; int paws_reject = 0; - tmp_opt.saw_tstamp = 0; if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { - tcp_parse_options(skb, &tmp_opt, 0); + tmp_opt.tstamp_ok = 1; + tcp_parse_options(skb, &tmp_opt, 1); if (tmp_opt.saw_tstamp) { tmp_opt.ts_recent = tcptw->tw_ts_recent; -- cgit v1.2.3 From 022c3f7d82f0f1c68018696f2f027b87b9bb45c2 Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 28 Oct 2009 04:15:22 +0000 Subject: Allow tcp_parse_options to consult dst entry We need tcp_parse_options to be aware of dst_entry to take into account per dst_entry TCP options settings Signed-off-by: Gilad Ben-Yossef Sigend-off-by: Ori Finkelman Sigend-off-by: Yony Amit Signed-off-by: David S. Miller --- include/net/tcp.h | 3 ++- net/ipv4/syncookies.c | 27 ++++++++++++++------------- net/ipv4/tcp_input.c | 9 ++++++--- net/ipv4/tcp_ipv4.c | 21 ++++++++++++--------- net/ipv4/tcp_minisocks.c | 7 +++++-- net/ipv6/syncookies.c | 28 +++++++++++++++------------- net/ipv6/tcp_ipv6.c | 3 ++- 7 files changed, 56 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 03a49c70337..740d09be8e2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -409,7 +409,8 @@ extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, extern void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, - int estab); + int estab, + struct dst_entry *dst); extern u8 *tcp_parse_md5sig_option(struct tcphdr *th); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 5ec678ad70e..3146cc40174 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -276,13 +276,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESRECV); - /* check for timestamp cookie support */ - memset(&tcp_opt, 0, sizeof(tcp_opt)); - tcp_parse_options(skb, &tcp_opt, 0); - - if (tcp_opt.saw_tstamp) - cookie_check_timestamp(&tcp_opt); - ret = NULL; req = inet_reqsk_alloc(&tcp_request_sock_ops); /* for safety */ if (!req) @@ -298,12 +291,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ireq->loc_addr = ip_hdr(skb)->daddr; ireq->rmt_addr = ip_hdr(skb)->saddr; ireq->ecn_ok = 0; - ireq->snd_wscale = tcp_opt.snd_wscale; - ireq->rcv_wscale = tcp_opt.rcv_wscale; - ireq->sack_ok = tcp_opt.sack_ok; - ireq->wscale_ok = tcp_opt.wscale_ok; - ireq->tstamp_ok = tcp_opt.saw_tstamp; - req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; /* We throwed the options of the initial SYN away, so we hope * the ACK carries the same options again (see RFC1122 4.2.3.8) @@ -352,6 +339,20 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, } } + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); + tcp_parse_options(skb, &tcp_opt, 0, &rt->u.dst); + + if (tcp_opt.saw_tstamp) + cookie_check_timestamp(&tcp_opt); + + ireq->snd_wscale = tcp_opt.snd_wscale; + ireq->rcv_wscale = tcp_opt.rcv_wscale; + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; + /* Try to redo what tcp_v4_send_synack did. */ req->window_clamp = tp->window_clamp ? :dst_metric(&rt->u.dst, RTAX_WINDOW); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a0c3700bae3..c7625005486 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3698,12 +3698,14 @@ old_ack: * the fast version below fails. */ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, - int estab) + int estab, struct dst_entry *dst) { unsigned char *ptr; struct tcphdr *th = tcp_hdr(skb); int length = (th->doff * 4) - sizeof(struct tcphdr); + BUG_ON(!estab && !dst); + ptr = (unsigned char *)(th + 1); opt_rx->saw_tstamp = 0; @@ -3820,7 +3822,7 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, if (tcp_parse_aligned_timestamp(tp, th)) return 1; } - tcp_parse_options(skb, &tp->rx_opt, 1); + tcp_parse_options(skb, &tp->rx_opt, 1, NULL); return 1; } @@ -5364,8 +5366,9 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); int saved_clamp = tp->rx_opt.mss_clamp; + struct dst_entry *dst = __sk_dst_get(sk); - tcp_parse_options(skb, &tp->rx_opt, 0); + tcp_parse_options(skb, &tp->rx_opt, 0, dst); if (th->ack) { /* rfc793: diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a4a3390a528..657ae334f12 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1257,11 +1257,21 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; #endif + ireq = inet_rsk(req); + ireq->loc_addr = daddr; + ireq->rmt_addr = saddr; + ireq->no_srccheck = inet_sk(sk)->transparent; + ireq->opt = tcp_v4_save_options(sk, skb); + + dst = inet_csk_route_req(sk, req); + if(!dst) + goto drop_and_free; + tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = 536; tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; - tcp_parse_options(skb, &tmp_opt, 0); + tcp_parse_options(skb, &tmp_opt, 0, dst); if (want_cookie && !tmp_opt.saw_tstamp) tcp_clear_options(&tmp_opt); @@ -1270,14 +1280,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_openreq_init(req, &tmp_opt, skb); - ireq = inet_rsk(req); - ireq->loc_addr = daddr; - ireq->rmt_addr = saddr; - ireq->no_srccheck = inet_sk(sk)->transparent; - ireq->opt = tcp_v4_save_options(sk, skb); - if (security_inet_conn_request(sk, skb, req)) - goto drop_and_free; + goto drop_and_release; if (!want_cookie) TCP_ECN_create_request(req, tcp_hdr(skb)); @@ -1302,7 +1306,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) */ if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle && - (dst = inet_csk_route_req(sk, req)) != NULL && (peer = rt_get_peer((struct rtable *)dst)) != NULL && peer->v4daddr == saddr) { if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL && diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 015e7c67dc8..463d51b53d3 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -102,7 +102,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { tmp_opt.tstamp_ok = 1; - tcp_parse_options(skb, &tmp_opt, 1); + tcp_parse_options(skb, &tmp_opt, 1, NULL); if (tmp_opt.saw_tstamp) { tmp_opt.ts_recent = tcptw->tw_ts_recent; @@ -500,10 +500,11 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, int paws_reject = 0; struct tcp_options_received tmp_opt; struct sock *child; + struct dst_entry *dst = inet_csk_route_req(sk, req); tmp_opt.saw_tstamp = 0; if (th->doff > (sizeof(struct tcphdr)>>2)) { - tcp_parse_options(skb, &tmp_opt, 0); + tcp_parse_options(skb, &tmp_opt, 0, dst); if (tmp_opt.saw_tstamp) { tmp_opt.ts_recent = req->ts_recent; @@ -516,6 +517,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, } } + dst_release(dst); + /* Check for pure retransmitted SYN. */ if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn && flg == TCP_FLAG_SYN && diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index c46da533888..612fc53e0bb 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -184,13 +184,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESRECV); - /* check for timestamp cookie support */ - memset(&tcp_opt, 0, sizeof(tcp_opt)); - tcp_parse_options(skb, &tcp_opt, 0); - - if (tcp_opt.saw_tstamp) - cookie_check_timestamp(&tcp_opt); - ret = NULL; req = inet6_reqsk_alloc(&tcp6_request_sock_ops); if (!req) @@ -224,12 +217,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) req->expires = 0UL; req->retrans = 0; ireq->ecn_ok = 0; - ireq->snd_wscale = tcp_opt.snd_wscale; - ireq->rcv_wscale = tcp_opt.rcv_wscale; - ireq->sack_ok = tcp_opt.sack_ok; - ireq->wscale_ok = tcp_opt.wscale_ok; - ireq->tstamp_ok = tcp_opt.saw_tstamp; - req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; treq->rcv_isn = ntohl(th->seq) - 1; treq->snt_isn = cookie; @@ -265,6 +252,21 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) goto out_free; } + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); + tcp_parse_options(skb, &tcp_opt, 0, dst); + + if (tcp_opt.saw_tstamp) + cookie_check_timestamp(&tcp_opt); + + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; + + ireq->snd_wscale = tcp_opt.snd_wscale; + ireq->rcv_wscale = tcp_opt.rcv_wscale; + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; + req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); tcp_select_initial_window(tcp_full_space(sk), req->mss, &req->rcv_wnd, &req->window_clamp, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c54ec3615de..34925f089e0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1167,6 +1167,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) struct tcp_sock *tp = tcp_sk(sk); struct request_sock *req = NULL; __u32 isn = TCP_SKB_CB(skb)->when; + struct dst_entry *dst = __sk_dst_get(sk); #ifdef CONFIG_SYN_COOKIES int want_cookie = 0; #else @@ -1205,7 +1206,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); tmp_opt.user_mss = tp->rx_opt.user_mss; - tcp_parse_options(skb, &tmp_opt, 0); + tcp_parse_options(skb, &tmp_opt, 0, dst); if (want_cookie && !tmp_opt.saw_tstamp) tcp_clear_options(&tmp_opt); -- cgit v1.2.3 From 1aba721eba1d84a2defce45b950272cee1e6c72a Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 28 Oct 2009 04:15:24 +0000 Subject: Add the no SACK route option feature Implement querying and acting upon the no sack bit in the features field. Signed-off-by: Gilad Ben-Yossef Sigend-off-by: Ori Finkelman Sigend-off-by: Yony Amit Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 +- net/ipv4/tcp_input.c | 3 ++- net/ipv4/tcp_output.c | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index adf2068d12b..9c802a6b04d 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -377,7 +377,7 @@ enum #define RTAX_MAX (__RTAX_MAX - 1) #define RTAX_FEATURE_ECN 0x00000001 -#define RTAX_FEATURE_SACK 0x00000002 +#define RTAX_FEATURE_NO_SACK 0x00000002 #define RTAX_FEATURE_TIMESTAMP 0x00000004 #define RTAX_FEATURE_ALLFRAG 0x00000008 diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c7625005486..5fb25f97745 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3763,7 +3763,8 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, break; case TCPOPT_SACK_PERM: if (opsize == TCPOLEN_SACK_PERM && th->syn && - !estab && sysctl_tcp_sack) { + !estab && sysctl_tcp_sack && + !dst_feature(dst, RTAX_FEATURE_NO_SACK)) { opt_rx->sack_ok = 1; tcp_sack_reset(opt_rx); } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2e2eb74ac4c..b35802af3c4 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -464,6 +464,7 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, struct tcp_md5sig_key **md5) { struct tcp_sock *tp = tcp_sk(sk); unsigned size = 0; + struct dst_entry *dst = __sk_dst_get(sk); #ifdef CONFIG_TCP_MD5SIG *md5 = tp->af_specific->md5_lookup(sk, sk); @@ -498,7 +499,8 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, opts->options |= OPTION_WSCALE; size += TCPOLEN_WSCALE_ALIGNED; } - if (likely(sysctl_tcp_sack)) { + if (likely(sysctl_tcp_sack && + !dst_feature(dst, RTAX_FEATURE_NO_SACK))) { opts->options |= OPTION_SACK_ADVERTISE; if (unlikely(!(OPTION_TS & opts->options))) size += TCPOLEN_SACKPERM_ALIGNED; -- cgit v1.2.3 From cda42ebd67ee5fdf09d7057b5a4584d36fe8a335 Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 28 Oct 2009 04:15:25 +0000 Subject: Allow disabling TCP timestamp options per route Implement querying and acting upon the no timestamp bit in the feature field. Signed-off-by: Gilad Ben-Yossef Sigend-off-by: Ori Finkelman Sigend-off-by: Yony Amit Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 +- net/ipv4/tcp_input.c | 3 ++- net/ipv4/tcp_output.c | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 9c802a6b04d..2ab8c758b46 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -378,7 +378,7 @@ enum #define RTAX_FEATURE_ECN 0x00000001 #define RTAX_FEATURE_NO_SACK 0x00000002 -#define RTAX_FEATURE_TIMESTAMP 0x00000004 +#define RTAX_FEATURE_NO_TSTAMP 0x00000004 #define RTAX_FEATURE_ALLFRAG 0x00000008 struct rta_session diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5fb25f97745..6097491aa9f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3755,7 +3755,8 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, case TCPOPT_TIMESTAMP: if ((opsize == TCPOLEN_TIMESTAMP) && ((estab && opt_rx->tstamp_ok) || - (!estab && sysctl_tcp_timestamps))) { + (!estab && sysctl_tcp_timestamps && + !dst_feature(dst, RTAX_FEATURE_NO_TSTAMP)))) { opt_rx->saw_tstamp = 1; opt_rx->rcv_tsval = get_unaligned_be32(ptr); opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b35802af3c4..8819eba8ebb 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -488,7 +488,9 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, opts->mss = tcp_advertise_mss(sk); size += TCPOLEN_MSS_ALIGNED; - if (likely(sysctl_tcp_timestamps && *md5 == NULL)) { + if (likely(sysctl_tcp_timestamps && + !dst_feature(dst, RTAX_FEATURE_NO_TSTAMP) && + *md5 == NULL)) { opts->options |= OPTION_TS; opts->tsval = TCP_SKB_CB(skb)->when; opts->tsecr = tp->rx_opt.ts_recent; @@ -2317,7 +2319,9 @@ static void tcp_connect_init(struct sock *sk) * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. */ tp->tcp_header_len = sizeof(struct tcphdr) + - (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); + (sysctl_tcp_timestamps && + (!dst_feature(dst, RTAX_FEATURE_NO_TSTAMP) ? + TCPOLEN_TSTAMP_ALIGNED : 0)); #ifdef CONFIG_TCP_MD5SIG if (tp->af_specific->md5_lookup(sk, sk) != NULL) -- cgit v1.2.3 From 345cda2fd695534be5a4494f1b59da9daed33663 Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 28 Oct 2009 04:15:26 +0000 Subject: Allow to turn off TCP window scale opt per route Add and use no window scale bit in the features field. Note that this is not the same as setting a window scale of 0 as would happen with window limit on route. Signed-off-by: Gilad Ben-Yossef Sigend-off-by: Ori Finkelman Sigend-off-by: Yony Amit Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 1 + net/ipv4/tcp_input.c | 3 ++- net/ipv4/tcp_output.c | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 2ab8c758b46..6784b342cbb 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -380,6 +380,7 @@ enum #define RTAX_FEATURE_NO_SACK 0x00000002 #define RTAX_FEATURE_NO_TSTAMP 0x00000004 #define RTAX_FEATURE_ALLFRAG 0x00000008 +#define RTAX_FEATURE_NO_WSCALE 0x00000010 struct rta_session { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6097491aa9f..393c56921dc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3739,7 +3739,8 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, break; case TCPOPT_WINDOW: if (opsize == TCPOLEN_WINDOW && th->syn && - !estab && sysctl_tcp_window_scaling) { + !estab && sysctl_tcp_window_scaling && + !dst_feature(dst, RTAX_FEATURE_NO_WSCALE)) { __u8 snd_wscale = *(__u8 *)ptr; opt_rx->wscale_ok = 1; if (snd_wscale > 14) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 8819eba8ebb..616c686ca25 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -496,7 +496,8 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, opts->tsecr = tp->rx_opt.ts_recent; size += TCPOLEN_TSTAMP_ALIGNED; } - if (likely(sysctl_tcp_window_scaling)) { + if (likely(sysctl_tcp_window_scaling && + !dst_feature(dst, RTAX_FEATURE_NO_WSCALE))) { opts->ws = tp->rx_opt.rcv_wscale; opts->options |= OPTION_WSCALE; size += TCPOLEN_WSCALE_ALIGNED; @@ -2347,7 +2348,8 @@ static void tcp_connect_init(struct sock *sk) tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), &tp->rcv_wnd, &tp->window_clamp, - sysctl_tcp_window_scaling, + (sysctl_tcp_window_scaling && + !dst_feature(dst, RTAX_FEATURE_NO_WSCALE)), &rcv_wscale); tp->rx_opt.rcv_wscale = rcv_wscale; -- cgit v1.2.3 From dc343475ed062e13fc260acccaab91d7d80fd5b2 Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 28 Oct 2009 04:15:27 +0000 Subject: Allow disabling of DSACK TCP option per route Add and use no DSCAK bit in the features field. Signed-off-by: Gilad Ben-Yossef Sigend-off-by: Ori Finkelman Sigend-off-by: Yony Amit Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 1 + net/ipv4/tcp_input.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 6784b342cbb..e78b60cd65a 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -381,6 +381,7 @@ enum #define RTAX_FEATURE_NO_TSTAMP 0x00000004 #define RTAX_FEATURE_ALLFRAG 0x00000008 #define RTAX_FEATURE_NO_WSCALE 0x00000010 +#define RTAX_FEATURE_NO_DSACK 0x00000020 struct rta_session { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 393c56921dc..ba0eab65fe8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4080,8 +4080,10 @@ static inline int tcp_sack_extend(struct tcp_sack_block *sp, u32 seq, static void tcp_dsack_set(struct sock *sk, u32 seq, u32 end_seq) { struct tcp_sock *tp = tcp_sk(sk); + struct dst_entry *dst = __sk_dst_get(sk); - if (tcp_is_sack(tp) && sysctl_tcp_dsack) { + if (tcp_is_sack(tp) && sysctl_tcp_dsack && + !dst_feature(dst, RTAX_FEATURE_NO_DSACK)) { int mib_idx; if (before(seq, tp->rcv_nxt)) @@ -4110,13 +4112,15 @@ static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq) static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); + struct dst_entry *dst = __sk_dst_get(sk); if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); tcp_enter_quickack_mode(sk); - if (tcp_is_sack(tp) && sysctl_tcp_dsack) { + if (tcp_is_sack(tp) && sysctl_tcp_dsack && + !dst_feature(dst, RTAX_FEATURE_NO_DSACK)) { u32 end_seq = TCP_SKB_CB(skb)->end_seq; if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) -- cgit v1.2.3 From 091bb8ab51c668635d1a75359019005921676881 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Fri, 23 Oct 2009 05:21:56 +0000 Subject: net: Cleanup redundant tests on unsigned If there is data, the unsigned skb->len is greater than 0. rt.sigdigits is unsigned as well, so the test `>= 0' is always true, the other part of the test catches wrapped values. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- net/x25/x25_in.c | 2 +- net/x25/x25_route.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index 7d7c3abf38b..96d92278354 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c @@ -114,7 +114,7 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp /* * Copy any Call User Data. */ - if (skb->len >= 0) { + if (skb->len > 0) { skb_copy_from_linear_data(skb, x25->calluserdata.cuddata, skb->len); diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c index 2c999ccf504..66961ea28c9 100644 --- a/net/x25/x25_route.c +++ b/net/x25/x25_route.c @@ -190,7 +190,7 @@ int x25_route_ioctl(unsigned int cmd, void __user *arg) goto out; rc = -EINVAL; - if (rt.sigdigits < 0 || rt.sigdigits > 15) + if (rt.sigdigits > 15) goto out; dev = x25_dev_get(rt.device); -- cgit v1.2.3 From 65a1c4fffaaf5ca166a1263d84ca664d5192cda6 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Fri, 23 Oct 2009 05:59:21 +0000 Subject: net: Cleanup redundant tests on unsigned optlen is unsigned so the `< 0' test is never true. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- net/can/raw.c | 2 -- net/compat.c | 3 --- net/ipv4/ip_sockglue.c | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) (limited to 'net') diff --git a/net/can/raw.c b/net/can/raw.c index 962fc9f1d0c..6e77db58b9e 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -424,8 +424,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, if (level != SOL_CAN_RAW) return -EINVAL; - if (optlen < 0) - return -EINVAL; switch (optname) { diff --git a/net/compat.c b/net/compat.c index e13f5256fd2..6a2f75fb3f4 100644 --- a/net/compat.c +++ b/net/compat.c @@ -390,9 +390,6 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, int err; struct socket *sock; - if (optlen < 0) - return -EINVAL; - if ((sock = sockfd_lookup(fd, &err))!=NULL) { err = security_socket_setsockopt(sock,level,optname); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index a72f43ce33b..cafad9baff0 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -480,7 +480,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, case IP_OPTIONS: { struct ip_options *opt = NULL; - if (optlen > 40 || optlen < 0) + if (optlen > 40) goto e_inval; err = ip_options_get_from_user(sock_net(sk), &opt, optval, optlen); -- cgit v1.2.3 From fb699dfd426a189fe33b91586c15176a75c8aed0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 19 Oct 2009 19:18:49 +0000 Subject: net: Introduce dev_get_by_index_rcu() Some workloads hit dev_base_lock rwlock pretty hard. We can use RCU lookups to avoid touching this rwlock. netdevices are already freed after a RCU grace period, so this patch adds no penalty at device dismantle time. dev_ifname() converted to dev_get_by_index_rcu() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 656110a46e9..ffc3106cc03 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1139,6 +1139,7 @@ extern void netdev_resync_ops(struct net_device *dev); extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev); extern struct net_device *dev_get_by_index(struct net *net, int ifindex); extern struct net_device *__dev_get_by_index(struct net *net, int ifindex); +extern struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); extern int dev_restart(struct net_device *dev); #ifdef CONFIG_NETPOLL_TRAP extern int netpoll_trap(void); diff --git a/net/core/dev.c b/net/core/dev.c index 09551cc143a..68a1bb68b5a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -214,12 +214,15 @@ static int list_netdevice(struct net_device *dev) write_lock_bh(&dev_base_lock); list_add_tail(&dev->dev_list, &net->dev_base_head); hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); - hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); + hlist_add_head_rcu(&dev->index_hlist, + dev_index_hash(net, dev->ifindex)); write_unlock_bh(&dev_base_lock); return 0; } -/* Device list removal */ +/* Device list removal + * caller must respect a RCU grace period before freeing/reusing dev + */ static void unlist_netdevice(struct net_device *dev) { ASSERT_RTNL(); @@ -228,7 +231,7 @@ static void unlist_netdevice(struct net_device *dev) write_lock_bh(&dev_base_lock); list_del(&dev->dev_list); hlist_del(&dev->name_hlist); - hlist_del(&dev->index_hlist); + hlist_del_rcu(&dev->index_hlist); write_unlock_bh(&dev_base_lock); } @@ -646,6 +649,31 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex) } EXPORT_SYMBOL(__dev_get_by_index); +/** + * dev_get_by_index_rcu - find a device by its ifindex + * @net: the applicable net namespace + * @ifindex: index of device + * + * Search for an interface by index. Returns %NULL if the device + * is not found or a pointer to the device. The device has not + * had its reference counter increased so the caller must be careful + * about locking. The caller must hold RCU lock. + */ + +struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex) +{ + struct hlist_node *p; + struct net_device *dev; + struct hlist_head *head = dev_index_hash(net, ifindex); + + hlist_for_each_entry_rcu(dev, p, head, index_hlist) + if (dev->ifindex == ifindex) + return dev; + + return NULL; +} +EXPORT_SYMBOL(dev_get_by_index_rcu); + /** * dev_get_by_index - find a device by its ifindex @@ -662,11 +690,11 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex) { struct net_device *dev; - read_lock(&dev_base_lock); - dev = __dev_get_by_index(net, ifindex); + rcu_read_lock(); + dev = dev_get_by_index_rcu(net, ifindex); if (dev) dev_hold(dev); - read_unlock(&dev_base_lock); + rcu_read_unlock(); return dev; } EXPORT_SYMBOL(dev_get_by_index); @@ -2939,15 +2967,15 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; - read_lock(&dev_base_lock); - dev = __dev_get_by_index(net, ifr.ifr_ifindex); + rcu_read_lock(); + dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); if (!dev) { - read_unlock(&dev_base_lock); + rcu_read_unlock(); return -ENODEV; } strcpy(ifr.ifr_name, dev->name); - read_unlock(&dev_base_lock); + rcu_read_unlock(); if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; -- cgit v1.2.3 From 38bfd8f5bec496e8e0db8849e01c99a33479418a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 29 Oct 2009 02:59:18 -0700 Subject: net,socket: introduce DECLARE_SOCKADDR helper to catch overflow at build time proto_ops->getname implies copying protocol specific data into storage unit (particulary to __kernel_sockaddr_storage). So when we implement new protocol support we should keep such a detail in mind (which is easy to forget about). Lets introduce DECLARE_SOCKADDR helper which check if storage unit is not overfowed at build time. Eventually inet_getname is switched to use DECLARE_SOCKADDR (to show example of usage). Signed-off-by: Cyrill Gorcunov Signed-off-by: David S. Miller --- include/linux/net.h | 3 +++ include/linux/socket.h | 3 +++ net/ipv4/af_inet.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/net.h b/include/linux/net.h index b42bb60fe92..4da9d571b05 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -199,6 +199,9 @@ struct proto_ops { struct pipe_inode_info *pipe, size_t len, unsigned int flags); }; +#define DECLARE_SOCKADDR(type, dst, src) \ + type dst = ({ __sockaddr_check_size(sizeof(*dst)); (type) src; }) + struct net_proto_family { int family; int (*create)(struct net *net, struct socket *sock, int protocol); diff --git a/include/linux/socket.h b/include/linux/socket.h index 59966f12990..7b3aae2052a 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -24,6 +24,9 @@ struct __kernel_sockaddr_storage { #include /* pid_t */ #include /* __user */ +#define __sockaddr_check_size(size) \ + BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage))) + #ifdef __KERNEL__ # ifdef CONFIG_PROC_FS struct seq_file; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 04a14b1600a..538e84d0bcb 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -685,7 +685,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, { struct sock *sk = sock->sk; struct inet_sock *inet = inet_sk(sk); - struct sockaddr_in *sin = (struct sockaddr_in *)uaddr; + DECLARE_SOCKADDR(struct sockaddr_in *, sin, uaddr); sin->sin_family = AF_INET; if (peer) { -- cgit v1.2.3 From aa3c487f355ff1477b8369d9f0b9860387ae21d4 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 29 Oct 2009 15:35:10 +0100 Subject: netfilter: xt_socket: make module available for INPUT chain This should make it possible to test for the existence of local sockets in the INPUT path. References: http://marc.info/?l=netfilter-devel&m=125380481517129&w=2 Signed-off-by: Jan Engelhardt Signed-off-by: Balazs Scheidler Signed-off-by: Patrick McHardy --- net/netfilter/xt_socket.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 362afbd60a9..6a902564d24 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -192,7 +192,8 @@ static struct xt_match socket_mt_reg[] __read_mostly = { .revision = 0, .family = NFPROTO_IPV4, .match = socket_mt_v0, - .hooks = 1 << NF_INET_PRE_ROUTING, + .hooks = (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_LOCAL_IN), .me = THIS_MODULE, }, { @@ -201,7 +202,8 @@ static struct xt_match socket_mt_reg[] __read_mostly = { .family = NFPROTO_IPV4, .match = socket_mt_v1, .matchsize = sizeof(struct xt_socket_mtinfo1), - .hooks = 1 << NF_INET_PRE_ROUTING, + .hooks = (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_LOCAL_IN), .me = THIS_MODULE, }, }; -- cgit v1.2.3 From 5b252f0c2f98df21fadf0f6cf189b87a0b938228 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 29 Oct 2009 07:17:09 +0000 Subject: gro: Name the GRO result enumeration type This clarifies which return and parameter types are GRO result codes and not RX result codes. Signed-off-by: Ben Hutchings Acked-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/netdevice.h | 10 ++++++---- net/8021q/vlan_core.c | 5 +++-- net/core/dev.c | 19 ++++++++++++++----- 3 files changed, 23 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ffc3106cc03..6e777efe149 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -348,13 +348,14 @@ enum NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */ }; -enum { +enum gro_result { GRO_MERGED, GRO_MERGED_FREE, GRO_HELD, GRO_NORMAL, GRO_DROP, }; +typedef enum gro_result gro_result_t; extern void __napi_schedule(struct napi_struct *n); @@ -1480,16 +1481,17 @@ extern int netif_rx_ni(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 extern int netif_receive_skb(struct sk_buff *skb); extern void napi_gro_flush(struct napi_struct *napi); -extern int dev_gro_receive(struct napi_struct *napi, +extern gro_result_t dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb); -extern int napi_skb_finish(int ret, struct sk_buff *skb); +extern int napi_skb_finish(gro_result_t ret, struct sk_buff *skb); extern int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb); extern void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb); extern struct sk_buff * napi_get_frags(struct napi_struct *napi); extern int napi_frags_finish(struct napi_struct *napi, - struct sk_buff *skb, int ret); + struct sk_buff *skb, + gro_result_t ret); extern struct sk_buff * napi_frags_skb(struct napi_struct *napi); extern int napi_gro_frags(struct napi_struct *napi); diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 7f7de1a04de..47a80d65c3b 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -74,8 +74,9 @@ u16 vlan_dev_vlan_id(const struct net_device *dev) } EXPORT_SYMBOL(vlan_dev_vlan_id); -static int vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci, struct sk_buff *skb) +static gro_result_t +vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, + unsigned int vlan_tci, struct sk_buff *skb) { struct sk_buff *p; diff --git a/net/core/dev.c b/net/core/dev.c index 68a1bb68b5a..1dc13744684 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2476,7 +2476,7 @@ void napi_gro_flush(struct napi_struct *napi) } EXPORT_SYMBOL(napi_gro_flush); -int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) +enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff **pp = NULL; struct packet_type *ptype; @@ -2484,7 +2484,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; int same_flow; int mac_len; - int ret; + enum gro_result ret; if (!(skb->dev->features & NETIF_F_GRO)) goto normal; @@ -2568,7 +2568,8 @@ normal: } EXPORT_SYMBOL(dev_gro_receive); -static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) +static gro_result_t +__napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff *p; @@ -2585,7 +2586,7 @@ static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) return dev_gro_receive(napi, skb); } -int napi_skb_finish(int ret, struct sk_buff *skb) +int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) { int err = NET_RX_SUCCESS; @@ -2600,6 +2601,10 @@ int napi_skb_finish(int ret, struct sk_buff *skb) case GRO_MERGED_FREE: kfree_skb(skb); break; + + case GRO_HELD: + case GRO_MERGED: + break; } return err; @@ -2652,7 +2657,8 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) } EXPORT_SYMBOL(napi_get_frags); -int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) +int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, + gro_result_t ret) { int err = NET_RX_SUCCESS; @@ -2674,6 +2680,9 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) case GRO_MERGED_FREE: napi_reuse_skb(napi, skb); break; + + case GRO_MERGED: + break; } return err; -- cgit v1.2.3 From c7c4b3b6e976b95facbb723951bdcd554a3530a4 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 29 Oct 2009 21:36:53 -0700 Subject: gro: Change all receive functions to return GRO result codes This will allow drivers to adjust their receive path dynamically based on whether GRO is being applied successfully. Currently all in-tree callers ignore the return values of these functions and do not need to be changed. Signed-off-by: Ben Hutchings Acked-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 25 ++++++++++++++----------- include/linux/netdevice.h | 8 ++++---- net/8021q/vlan_core.c | 16 +++++++++------- net/core/dev.c | 38 +++++++++++++++----------------------- 4 files changed, 42 insertions(+), 45 deletions(-) (limited to 'net') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 71a4870c09a..153f6b9e722 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -120,10 +120,12 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev); extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, u16 vlan_tci, int polling); extern int vlan_hwaccel_do_receive(struct sk_buff *skb); -extern int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci, struct sk_buff *skb); -extern int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci); +extern gro_result_t +vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, + unsigned int vlan_tci, struct sk_buff *skb); +extern gro_result_t +vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, + unsigned int vlan_tci); #else static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) @@ -150,17 +152,18 @@ static inline int vlan_hwaccel_do_receive(struct sk_buff *skb) return 0; } -static inline int vlan_gro_receive(struct napi_struct *napi, - struct vlan_group *grp, - unsigned int vlan_tci, struct sk_buff *skb) +static inline gro_result_t +vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, + unsigned int vlan_tci, struct sk_buff *skb) { - return NET_RX_DROP; + return GRO_DROP; } -static inline int vlan_gro_frags(struct napi_struct *napi, - struct vlan_group *grp, unsigned int vlan_tci) +static inline gro_result_t +vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, + unsigned int vlan_tci) { - return NET_RX_DROP; + return GRO_DROP; } #endif diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 6e777efe149..193b637889f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1483,17 +1483,17 @@ extern int netif_receive_skb(struct sk_buff *skb); extern void napi_gro_flush(struct napi_struct *napi); extern gro_result_t dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb); -extern int napi_skb_finish(gro_result_t ret, struct sk_buff *skb); -extern int napi_gro_receive(struct napi_struct *napi, +extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb); +extern gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb); extern void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb); extern struct sk_buff * napi_get_frags(struct napi_struct *napi); -extern int napi_frags_finish(struct napi_struct *napi, +extern gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, gro_result_t ret); extern struct sk_buff * napi_frags_skb(struct napi_struct *napi); -extern int napi_gro_frags(struct napi_struct *napi); +extern gro_result_t napi_gro_frags(struct napi_struct *napi); static inline void napi_free_frags(struct napi_struct *napi) { diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 47a80d65c3b..8d5ca2ac4f8 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -102,11 +102,12 @@ drop: return GRO_DROP; } -int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci, struct sk_buff *skb) +gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, + unsigned int vlan_tci, struct sk_buff *skb) { if (netpoll_rx_on(skb)) - return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); + return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) + ? GRO_DROP : GRO_NORMAL; skb_gro_reset_offset(skb); @@ -114,17 +115,18 @@ int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, } EXPORT_SYMBOL(vlan_gro_receive); -int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci) +gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, + unsigned int vlan_tci) { struct sk_buff *skb = napi_frags_skb(napi); if (!skb) - return NET_RX_DROP; + return GRO_DROP; if (netpoll_rx_on(skb)) { skb->protocol = eth_type_trans(skb, skb->dev); - return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); + return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) + ? GRO_DROP : GRO_NORMAL; } return napi_frags_finish(napi, skb, diff --git a/net/core/dev.c b/net/core/dev.c index 1dc13744684..631cc40da19 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2586,18 +2586,15 @@ __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) return dev_gro_receive(napi, skb); } -int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) +gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) { - int err = NET_RX_SUCCESS; - switch (ret) { case GRO_NORMAL: - return netif_receive_skb(skb); + if (netif_receive_skb(skb)) + ret = GRO_DROP; + break; case GRO_DROP: - err = NET_RX_DROP; - /* fall through */ - case GRO_MERGED_FREE: kfree_skb(skb); break; @@ -2607,7 +2604,7 @@ int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) break; } - return err; + return ret; } EXPORT_SYMBOL(napi_skb_finish); @@ -2627,7 +2624,7 @@ void skb_gro_reset_offset(struct sk_buff *skb) } EXPORT_SYMBOL(skb_gro_reset_offset); -int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) +gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { skb_gro_reset_offset(skb); @@ -2657,26 +2654,21 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) } EXPORT_SYMBOL(napi_get_frags); -int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, - gro_result_t ret) +gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, + gro_result_t ret) { - int err = NET_RX_SUCCESS; - switch (ret) { case GRO_NORMAL: case GRO_HELD: skb->protocol = eth_type_trans(skb, napi->dev); - if (ret == GRO_NORMAL) - return netif_receive_skb(skb); - - skb_gro_pull(skb, -ETH_HLEN); + if (ret == GRO_HELD) + skb_gro_pull(skb, -ETH_HLEN); + else if (netif_receive_skb(skb)) + ret = GRO_DROP; break; case GRO_DROP: - err = NET_RX_DROP; - /* fall through */ - case GRO_MERGED_FREE: napi_reuse_skb(napi, skb); break; @@ -2685,7 +2677,7 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, break; } - return err; + return ret; } EXPORT_SYMBOL(napi_frags_finish); @@ -2726,12 +2718,12 @@ out: } EXPORT_SYMBOL(napi_frags_skb); -int napi_gro_frags(struct napi_struct *napi) +gro_result_t napi_gro_frags(struct napi_struct *napi) { struct sk_buff *skb = napi_frags_skb(napi); if (!skb) - return NET_RX_DROP; + return GRO_DROP; return napi_frags_finish(napi, skb, __napi_gro_receive(napi, skb)); } -- cgit v1.2.3 From 43ab85021e8286e1641928ab3cc542dd1e8c7f94 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Wed, 14 Oct 2009 05:26:30 +0000 Subject: ax25: unsigned cannot be less than 0 in ax25_ctl_ioctl() struct ax25_ctl_struct member `arg' is unsigned and cannot be less than 0. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- net/ax25/af_ax25.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index f05306f168f..f1e998b2796 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -369,6 +369,9 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) if (ax25_ctl.digi_count > AX25_MAX_DIGIS) return -EINVAL; + if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL) + return -EINVAL; + digi.ndigi = ax25_ctl.digi_count; for (k = 0; k < digi.ndigi; k++) digi.calls[k] = ax25_ctl.digi_addr[k]; @@ -418,14 +421,10 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) break; case AX25_T3: - if (ax25_ctl.arg < 0) - goto einval_put; ax25->t3 = ax25_ctl.arg * HZ; break; case AX25_IDLE: - if (ax25_ctl.arg < 0) - goto einval_put; ax25->idle = ax25_ctl.arg * 60 * HZ; break; -- cgit v1.2.3 From 29906f6a427d2004a515ebbcdc7b28bae8f6c19c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 29 Oct 2009 23:43:00 -0700 Subject: vlan: cleanup multiple unregistrations The temporary copy of the VLAN group is not neccessary since the lower device is already in the process of being unregistered, if it was neccessary the memset of the global group would introduce a race condition. With this removed, the changes to the original code are only a few lines, so remove the new function and move the code back into vlan_device_event(). Signed-off-by: Patrick McHardy Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlan.c | 52 ++++++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 511afe72af3..39f8d012010 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -161,10 +161,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) grp->nr_vlans--; - if (!grp->killall) { - vlan_group_set_device(grp, vlan_id, NULL); + vlan_group_set_device(grp, vlan_id, NULL); + if (!grp->killall) synchronize_net(); - } + unregister_netdevice_queue(dev, head); /* If the group is now empty, kill off the group. */ @@ -184,34 +184,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) dev_put(real_dev); } -void unregister_vlan_dev_alls(struct vlan_group *grp) -{ - LIST_HEAD(list); - int i; - struct net_device *vlandev; - struct vlan_group save; - - memcpy(&save, grp, sizeof(save)); - memset(&grp->vlan_devices_arrays, 0, sizeof(grp->vlan_devices_arrays)); - grp->killall = 1; - - synchronize_net(); - - /* Delete all VLANs for this dev. */ - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - vlandev = vlan_group_get_device(&save, i); - if (!vlandev) - continue; - - unregister_vlan_dev(vlandev, &list); - if (grp->nr_vlans == 0) - break; - } - unregister_netdevice_many(&list); - for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) - kfree(save.vlan_devices_arrays[i]); -} - static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) { @@ -456,6 +428,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, struct vlan_group *grp; int i, flgs; struct net_device *vlandev; + LIST_HEAD(list); if (is_vlan_dev(dev)) __vlan_device_event(dev, event); @@ -553,7 +526,22 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, break; case NETDEV_UNREGISTER: - unregister_vlan_dev_alls(grp); + /* Delete all VLANs for this dev. */ + grp->killall = 1; + + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + vlandev = vlan_group_get_device(grp, i); + if (!vlandev) + continue; + + /* unregistration of last vlan destroys group, abort + * afterwards */ + if (grp->nr_vlans == 1) + i = VLAN_GROUP_ARRAY_LEN; + + unregister_vlan_dev(vlandev, &list); + } + unregister_netdevice_many(&list); break; } -- cgit v1.2.3 From 0bd8d53656da72bc065766b5f2a05ca738020b8a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 30 Oct 2009 01:40:11 -0700 Subject: net: use hlist_for_each_entry() Small cleanup of __dev_get_by_name() and __dev_get_by_index() to use hlist_for_each_entry() : They'll look like their _rcu variant. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 631cc40da19..94f42a15fff 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -587,13 +587,13 @@ __setup("netdev=", netdev_boot_setup); struct net_device *__dev_get_by_name(struct net *net, const char *name) { struct hlist_node *p; + struct net_device *dev; + struct hlist_head *head = dev_name_hash(net, name); - hlist_for_each(p, dev_name_hash(net, name)) { - struct net_device *dev - = hlist_entry(p, struct net_device, name_hlist); + hlist_for_each_entry(dev, p, head, name_hlist) if (!strncmp(dev->name, name, IFNAMSIZ)) return dev; - } + return NULL; } EXPORT_SYMBOL(__dev_get_by_name); @@ -638,13 +638,13 @@ EXPORT_SYMBOL(dev_get_by_name); struct net_device *__dev_get_by_index(struct net *net, int ifindex) { struct hlist_node *p; + struct net_device *dev; + struct hlist_head *head = dev_index_hash(net, ifindex); - hlist_for_each(p, dev_index_hash(net, ifindex)) { - struct net_device *dev - = hlist_entry(p, struct net_device, index_hlist); + hlist_for_each_entry(dev, p, head, index_hlist) if (dev->ifindex == ifindex) return dev; - } + return NULL; } EXPORT_SYMBOL(__dev_get_by_index); -- cgit v1.2.3 From 0c509a6c9393b27a8c5a01acd4a72616206cfc24 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 29 Oct 2009 14:18:21 +0000 Subject: net: Allow devices to specify a device specific sysfs group. This isn't beautifully abstracted, but it is simple, simplifies uses and so far is only needed for the bonding driver. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 ++-- net/core/net-sysfs.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 193b637889f..e5ece8dceaa 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -900,8 +900,8 @@ struct net_device /* class/net/name entry */ struct device dev; - /* space for optional statistics and wireless sysfs groups */ - const struct attribute_group *sysfs_groups[3]; + /* space for optional device, statistics, and wireless sysfs groups */ + const struct attribute_group *sysfs_groups[4]; /* rtnetlink link ops */ const struct rtnl_link_ops *rtnl_link_ops; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 89de182353b..157645c0da7 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -544,8 +544,11 @@ int netdev_register_kobject(struct net_device *net) dev_set_name(dev, "%s", net->name); #ifdef CONFIG_SYSFS - *groups++ = &netstat_group; + /* Allow for a device specific group */ + if (*groups) + groups++; + *groups++ = &netstat_group; #ifdef CONFIG_WIRELESS_EXT_SYSFS if (net->ieee80211_ptr) *groups++ = &wireless_group; -- cgit v1.2.3 From 7bcfaf2f431c09c51fe776fc06638b25d3b421c5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 27 Oct 2009 12:59:03 +0100 Subject: cfg80211/mac80211: use debugfs_remove_recursive We can save a lot of code and pointers in the structs by using debugfs_remove_recursive(). First, change cfg80211 to use debugfs_remove_recursive() so that drivers do not need to clean up any files they added to the per-wiphy debugfs (if and only if they are ok to be accessed until after wiphy_unregister!). Then also make mac80211 use debugfs_remove_recursive() where necessary -- it need not remove per-wiphy files as cfg80211 now removes those, but netdev etc. files still need to be handled but can now be removed without needing struct dentry pointers to all of them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs.c | 73 +----------------- net/mac80211/debugfs.h | 2 - net/mac80211/debugfs_key.c | 44 ++++------- net/mac80211/debugfs_netdev.c | 174 +++++++----------------------------------- net/mac80211/debugfs_sta.c | 31 +------- net/mac80211/ieee80211_i.h | 114 +-------------------------- net/mac80211/key.h | 12 --- net/mac80211/main.c | 2 - net/mac80211/rate.c | 7 +- net/mac80211/sta_info.h | 22 ------ net/wireless/core.c | 3 +- net/wireless/core.h | 11 --- net/wireless/debugfs.c | 15 +--- net/wireless/debugfs.h | 3 - 14 files changed, 51 insertions(+), 462 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 96991b68f04..82c807723b6 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -1,3 +1,4 @@ + /* * mac80211 debugfs for wireless PHYs * @@ -38,16 +39,10 @@ static const struct file_operations name## _ops = { \ }; #define DEBUGFS_ADD(name) \ - local->debugfs.name = debugfs_create_file(#name, 0400, phyd, \ - local, &name## _ops); + debugfs_create_file(#name, 0400, phyd, local, &name## _ops); #define DEBUGFS_ADD_MODE(name, mode) \ - local->debugfs.name = debugfs_create_file(#name, mode, phyd, \ - local, &name## _ops); - -#define DEBUGFS_DEL(name) \ - debugfs_remove(local->debugfs.name); \ - local->debugfs.name = NULL; + debugfs_create_file(#name, mode, phyd, local, &name## _ops); DEBUGFS_READONLY_FILE(frequency, 20, "%d", @@ -233,12 +228,7 @@ static const struct file_operations stats_ ##name## _ops = { \ }; #define DEBUGFS_STATS_ADD(name) \ - local->debugfs.stats.name = debugfs_create_file(#name, 0400, statsd,\ - local, &stats_ ##name## _ops); - -#define DEBUGFS_STATS_DEL(name) \ - debugfs_remove(local->debugfs.stats.name); \ - local->debugfs.stats.name = NULL; + debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops); DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u", local->dot11TransmittedFragmentCount); @@ -326,7 +316,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(noack); statsd = debugfs_create_dir("statistics", phyd); - local->debugfs.statistics = statsd; /* if the dir failed, don't put all the other things into the root! */ if (!statsd) @@ -367,57 +356,3 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_STATS_ADD(dot11FCSErrorCount); DEBUGFS_STATS_ADD(dot11RTSSuccessCount); } - -void debugfs_hw_del(struct ieee80211_local *local) -{ - DEBUGFS_DEL(frequency); - DEBUGFS_DEL(total_ps_buffered); - DEBUGFS_DEL(wep_iv); - DEBUGFS_DEL(tsf); - DEBUGFS_DEL(queues); - DEBUGFS_DEL(reset); - DEBUGFS_DEL(noack); - - DEBUGFS_STATS_DEL(transmitted_fragment_count); - DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); - DEBUGFS_STATS_DEL(failed_count); - DEBUGFS_STATS_DEL(retry_count); - DEBUGFS_STATS_DEL(multiple_retry_count); - DEBUGFS_STATS_DEL(frame_duplicate_count); - DEBUGFS_STATS_DEL(received_fragment_count); - DEBUGFS_STATS_DEL(multicast_received_frame_count); - DEBUGFS_STATS_DEL(transmitted_frame_count); - DEBUGFS_STATS_DEL(num_scans); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_STATS_DEL(tx_handlers_drop); - DEBUGFS_STATS_DEL(tx_handlers_queued); - DEBUGFS_STATS_DEL(tx_handlers_drop_unencrypted); - DEBUGFS_STATS_DEL(tx_handlers_drop_fragment); - DEBUGFS_STATS_DEL(tx_handlers_drop_wep); - DEBUGFS_STATS_DEL(tx_handlers_drop_not_assoc); - DEBUGFS_STATS_DEL(tx_handlers_drop_unauth_port); - DEBUGFS_STATS_DEL(rx_handlers_drop); - DEBUGFS_STATS_DEL(rx_handlers_queued); - DEBUGFS_STATS_DEL(rx_handlers_drop_nullfunc); - DEBUGFS_STATS_DEL(rx_handlers_drop_defrag); - DEBUGFS_STATS_DEL(rx_handlers_drop_short); - DEBUGFS_STATS_DEL(rx_handlers_drop_passive_scan); - DEBUGFS_STATS_DEL(tx_expand_skb_head); - DEBUGFS_STATS_DEL(tx_expand_skb_head_cloned); - DEBUGFS_STATS_DEL(rx_expand_skb_head); - DEBUGFS_STATS_DEL(rx_expand_skb_head2); - DEBUGFS_STATS_DEL(rx_handlers_fragments); - DEBUGFS_STATS_DEL(tx_status_drop); -#endif - DEBUGFS_STATS_DEL(dot11ACKFailureCount); - DEBUGFS_STATS_DEL(dot11RTSFailureCount); - DEBUGFS_STATS_DEL(dot11FCSErrorCount); - DEBUGFS_STATS_DEL(dot11RTSSuccessCount); - - debugfs_remove(local->debugfs.statistics); - local->debugfs.statistics = NULL; - debugfs_remove(local->debugfs.stations); - local->debugfs.stations = NULL; - debugfs_remove(local->debugfs.keys); - local->debugfs.keys = NULL; -} diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index dd2541935c2..68e6a2050f9 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h @@ -3,14 +3,12 @@ #ifdef CONFIG_MAC80211_DEBUGFS extern void debugfs_hw_add(struct ieee80211_local *local); -extern void debugfs_hw_del(struct ieee80211_local *local); extern int mac80211_open_file_generic(struct inode *inode, struct file *file); #else static inline void debugfs_hw_add(struct ieee80211_local *local) { return; } -static inline void debugfs_hw_del(struct ieee80211_local *local) {} #endif #endif /* __MAC80211_DEBUGFS_H */ diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 99c752588b3..e0f5224630d 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -225,8 +225,8 @@ static ssize_t key_key_read(struct file *file, char __user *userbuf, KEY_OPS(key); #define DEBUGFS_ADD(name) \ - key->debugfs.name = debugfs_create_file(#name, 0400,\ - key->debugfs.dir, key, &key_##name##_ops); + debugfs_create_file(#name, 0400, key->debugfs.dir, \ + key, &key_##name##_ops); void ieee80211_debugfs_key_add(struct ieee80211_key *key) { @@ -271,30 +271,12 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) DEBUGFS_ADD(ifindex); }; -#define DEBUGFS_DEL(name) \ - debugfs_remove(key->debugfs.name); key->debugfs.name = NULL; - void ieee80211_debugfs_key_remove(struct ieee80211_key *key) { if (!key) return; - DEBUGFS_DEL(keylen); - DEBUGFS_DEL(flags); - DEBUGFS_DEL(keyidx); - DEBUGFS_DEL(hw_key_idx); - DEBUGFS_DEL(tx_rx_count); - DEBUGFS_DEL(algorithm); - DEBUGFS_DEL(tx_spec); - DEBUGFS_DEL(rx_spec); - DEBUGFS_DEL(replays); - DEBUGFS_DEL(icverrors); - DEBUGFS_DEL(key); - DEBUGFS_DEL(ifindex); - - debugfs_remove(key->debugfs.stalink); - key->debugfs.stalink = NULL; - debugfs_remove(key->debugfs.dir); + debugfs_remove_recursive(key->debugfs.dir); key->debugfs.dir = NULL; } void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) @@ -302,7 +284,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) char buf[50]; struct ieee80211_key *key; - if (!sdata->debugfsdir) + if (!sdata->debugfs.dir) return; /* this is running under the key lock */ @@ -310,9 +292,9 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) key = sdata->default_key; if (key) { sprintf(buf, "../keys/%d", key->debugfs.cnt); - sdata->common_debugfs.default_key = + sdata->debugfs.default_key = debugfs_create_symlink("default_key", - sdata->debugfsdir, buf); + sdata->debugfs.dir, buf); } else ieee80211_debugfs_key_remove_default(sdata); } @@ -322,8 +304,8 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) if (!sdata) return; - debugfs_remove(sdata->common_debugfs.default_key); - sdata->common_debugfs.default_key = NULL; + debugfs_remove(sdata->debugfs.default_key); + sdata->debugfs.default_key = NULL; } void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) @@ -331,7 +313,7 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) char buf[50]; struct ieee80211_key *key; - if (!sdata->debugfsdir) + if (!sdata->debugfs.dir) return; /* this is running under the key lock */ @@ -339,9 +321,9 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) key = sdata->default_mgmt_key; if (key) { sprintf(buf, "../keys/%d", key->debugfs.cnt); - sdata->common_debugfs.default_mgmt_key = + sdata->debugfs.default_mgmt_key = debugfs_create_symlink("default_mgmt_key", - sdata->debugfsdir, buf); + sdata->debugfs.dir, buf); } else ieee80211_debugfs_key_remove_mgmt_default(sdata); } @@ -351,8 +333,8 @@ void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sda if (!sdata) return; - debugfs_remove(sdata->common_debugfs.default_mgmt_key); - sdata->common_debugfs.default_mgmt_key = NULL; + debugfs_remove(sdata->debugfs.default_mgmt_key); + sdata->debugfs.default_mgmt_key = NULL; } void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 61234e79022..8782264f49e 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -152,9 +152,9 @@ IEEE80211_IF_FILE(min_discovery_timeout, #endif -#define DEBUGFS_ADD(name, type)\ - sdata->debugfs.type.name = debugfs_create_file(#name, 0400,\ - sdata->debugfsdir, sdata, &name##_ops); +#define DEBUGFS_ADD(name, type) \ + debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ + sdata, &name##_ops); static void add_sta_files(struct ieee80211_sub_if_data *sdata) { @@ -199,30 +199,32 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata) } #ifdef CONFIG_MAC80211_MESH -#define MESHSTATS_ADD(name)\ - sdata->mesh_stats.name = debugfs_create_file(#name, 0400,\ - sdata->mesh_stats_dir, sdata, &name##_ops); static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) { - sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", - sdata->debugfsdir); + struct dentry *dir = debugfs_create_dir("mesh_stats", + sdata->debugfs.dir); + +#define MESHSTATS_ADD(name)\ + debugfs_create_file(#name, 0400, dir, sdata, &name##_ops); + MESHSTATS_ADD(fwded_mcast); MESHSTATS_ADD(fwded_unicast); MESHSTATS_ADD(fwded_frames); MESHSTATS_ADD(dropped_frames_ttl); MESHSTATS_ADD(dropped_frames_no_route); MESHSTATS_ADD(estab_plinks); +#undef MESHSTATS_ADD } -#define MESHPARAMS_ADD(name)\ - sdata->mesh_config.name = debugfs_create_file(#name, 0600,\ - sdata->mesh_config_dir, sdata, &name##_ops); - static void add_mesh_config(struct ieee80211_sub_if_data *sdata) { - sdata->mesh_config_dir = debugfs_create_dir("mesh_config", - sdata->debugfsdir); + struct dentry *dir = debugfs_create_dir("mesh_config", + sdata->debugfs.dir); + +#define MESHPARAMS_ADD(name) \ + debugfs_create_file(#name, 0600, dir, sdata, &name##_ops); + MESHPARAMS_ADD(dot11MeshMaxRetries); MESHPARAMS_ADD(dot11MeshRetryTimeout); MESHPARAMS_ADD(dot11MeshConfirmTimeout); @@ -236,12 +238,14 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries); MESHPARAMS_ADD(path_refresh_time); MESHPARAMS_ADD(min_discovery_timeout); + +#undef MESHPARAMS_ADD } #endif static void add_files(struct ieee80211_sub_if_data *sdata) { - if (!sdata->debugfsdir) + if (!sdata->debugfs.dir) return; switch (sdata->vif.type) { @@ -274,134 +278,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata) } } -#define DEBUGFS_DEL(name, type) \ - do { \ - debugfs_remove(sdata->debugfs.type.name); \ - sdata->debugfs.type.name = NULL; \ - } while (0) - -static void del_sta_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, sta); - DEBUGFS_DEL(force_unicast_rateidx, sta); - DEBUGFS_DEL(max_ratectrl_rateidx, sta); - - DEBUGFS_DEL(bssid, sta); - DEBUGFS_DEL(aid, sta); - DEBUGFS_DEL(capab, sta); -} - -static void del_ap_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, ap); - DEBUGFS_DEL(force_unicast_rateidx, ap); - DEBUGFS_DEL(max_ratectrl_rateidx, ap); - - DEBUGFS_DEL(num_sta_ps, ap); - DEBUGFS_DEL(dtim_count, ap); - DEBUGFS_DEL(num_buffered_multicast, ap); -} - -static void del_wds_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, wds); - DEBUGFS_DEL(force_unicast_rateidx, wds); - DEBUGFS_DEL(max_ratectrl_rateidx, wds); - - DEBUGFS_DEL(peer, wds); -} - -static void del_vlan_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, vlan); - DEBUGFS_DEL(force_unicast_rateidx, vlan); - DEBUGFS_DEL(max_ratectrl_rateidx, vlan); -} - -static void del_monitor_files(struct ieee80211_sub_if_data *sdata) -{ -} - -#ifdef CONFIG_MAC80211_MESH -#define MESHSTATS_DEL(name) \ - do { \ - debugfs_remove(sdata->mesh_stats.name); \ - sdata->mesh_stats.name = NULL; \ - } while (0) - -static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) -{ - MESHSTATS_DEL(fwded_mcast); - MESHSTATS_DEL(fwded_unicast); - MESHSTATS_DEL(fwded_frames); - MESHSTATS_DEL(dropped_frames_ttl); - MESHSTATS_DEL(dropped_frames_no_route); - MESHSTATS_DEL(estab_plinks); - debugfs_remove(sdata->mesh_stats_dir); - sdata->mesh_stats_dir = NULL; -} - -#define MESHPARAMS_DEL(name) \ - do { \ - debugfs_remove(sdata->mesh_config.name); \ - sdata->mesh_config.name = NULL; \ - } while (0) - -static void del_mesh_config(struct ieee80211_sub_if_data *sdata) -{ - MESHPARAMS_DEL(dot11MeshMaxRetries); - MESHPARAMS_DEL(dot11MeshRetryTimeout); - MESHPARAMS_DEL(dot11MeshConfirmTimeout); - MESHPARAMS_DEL(dot11MeshHoldingTimeout); - MESHPARAMS_DEL(dot11MeshTTL); - MESHPARAMS_DEL(auto_open_plinks); - MESHPARAMS_DEL(dot11MeshMaxPeerLinks); - MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout); - MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval); - MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime); - MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries); - MESHPARAMS_DEL(path_refresh_time); - MESHPARAMS_DEL(min_discovery_timeout); - debugfs_remove(sdata->mesh_config_dir); - sdata->mesh_config_dir = NULL; -} -#endif - -static void del_files(struct ieee80211_sub_if_data *sdata) -{ - if (!sdata->debugfsdir) - return; - - switch (sdata->vif.type) { - case NL80211_IFTYPE_MESH_POINT: -#ifdef CONFIG_MAC80211_MESH - del_mesh_stats(sdata); - del_mesh_config(sdata); -#endif - break; - case NL80211_IFTYPE_STATION: - del_sta_files(sdata); - break; - case NL80211_IFTYPE_ADHOC: - /* XXX */ - break; - case NL80211_IFTYPE_AP: - del_ap_files(sdata); - break; - case NL80211_IFTYPE_WDS: - del_wds_files(sdata); - break; - case NL80211_IFTYPE_MONITOR: - del_monitor_files(sdata); - break; - case NL80211_IFTYPE_AP_VLAN: - del_vlan_files(sdata); - break; - default: - break; - } -} - static int notif_registered; void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) @@ -412,16 +288,18 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) return; sprintf(buf, "netdev:%s", sdata->dev->name); - sdata->debugfsdir = debugfs_create_dir(buf, + sdata->debugfs.dir = debugfs_create_dir(buf, sdata->local->hw.wiphy->debugfsdir); add_files(sdata); } void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) { - del_files(sdata); - debugfs_remove(sdata->debugfsdir); - sdata->debugfsdir = NULL; + if (!sdata->debugfs.dir) + return; + + debugfs_remove_recursive(sdata->debugfs.dir); + sdata->debugfs.dir = NULL; } static int netdev_notify(struct notifier_block *nb, @@ -444,7 +322,7 @@ static int netdev_notify(struct notifier_block *nb, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - dir = sdata->debugfsdir; + dir = sdata->debugfs.dir; if (!dir) return 0; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 33a2e892115..8721679773d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -158,13 +158,9 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, STA_OPS(agg_status); #define DEBUGFS_ADD(name) \ - sta->debugfs.name = debugfs_create_file(#name, 0400, \ + debugfs_create_file(#name, 0400, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); -#define DEBUGFS_DEL(name) \ - debugfs_remove(sta->debugfs.name);\ - sta->debugfs.name = NULL; - void ieee80211_sta_debugfs_add(struct sta_info *sta) { @@ -216,29 +212,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) void ieee80211_sta_debugfs_remove(struct sta_info *sta) { - DEBUGFS_DEL(flags); - DEBUGFS_DEL(num_ps_buf_frames); - DEBUGFS_DEL(inactive_ms); - DEBUGFS_DEL(last_seq_ctrl); - DEBUGFS_DEL(agg_status); - DEBUGFS_DEL(aid); - DEBUGFS_DEL(dev); - DEBUGFS_DEL(rx_packets); - DEBUGFS_DEL(tx_packets); - DEBUGFS_DEL(rx_bytes); - DEBUGFS_DEL(tx_bytes); - DEBUGFS_DEL(rx_duplicates); - DEBUGFS_DEL(rx_fragments); - DEBUGFS_DEL(rx_dropped); - DEBUGFS_DEL(tx_fragments); - DEBUGFS_DEL(tx_filtered); - DEBUGFS_DEL(tx_retry_failed); - DEBUGFS_DEL(tx_retry_count); - DEBUGFS_DEL(last_signal); - DEBUGFS_DEL(last_qual); - DEBUGFS_DEL(last_noise); - DEBUGFS_DEL(wep_weak_iv_count); - - debugfs_remove(sta->debugfs.dir); + debugfs_remove_recursive(sta->debugfs.dir); sta->debugfs.dir = NULL; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 588005c84a6..60c2822802f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -471,74 +471,11 @@ struct ieee80211_sub_if_data { } u; #ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *debugfsdir; - union { - struct { - struct dentry *drop_unencrypted; - struct dentry *bssid; - struct dentry *aid; - struct dentry *capab; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - } sta; - struct { - struct dentry *drop_unencrypted; - struct dentry *num_sta_ps; - struct dentry *dtim_count; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - struct dentry *num_buffered_multicast; - } ap; - struct { - struct dentry *drop_unencrypted; - struct dentry *peer; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - } wds; - struct { - struct dentry *drop_unencrypted; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - } vlan; - struct { - struct dentry *mode; - } monitor; - } debugfs; struct { + struct dentry *dir; struct dentry *default_key; struct dentry *default_mgmt_key; - } common_debugfs; - -#ifdef CONFIG_MAC80211_MESH - struct dentry *mesh_stats_dir; - struct { - struct dentry *fwded_mcast; - struct dentry *fwded_unicast; - struct dentry *fwded_frames; - struct dentry *dropped_frames_ttl; - struct dentry *dropped_frames_no_route; - struct dentry *estab_plinks; - struct timer_list mesh_path_timer; - } mesh_stats; - - struct dentry *mesh_config_dir; - struct { - struct dentry *dot11MeshRetryTimeout; - struct dentry *dot11MeshConfirmTimeout; - struct dentry *dot11MeshHoldingTimeout; - struct dentry *dot11MeshMaxRetries; - struct dentry *dot11MeshTTL; - struct dentry *auto_open_plinks; - struct dentry *dot11MeshMaxPeerLinks; - struct dentry *dot11MeshHWMPactivePathTimeout; - struct dentry *dot11MeshHWMPpreqMinInterval; - struct dentry *dot11MeshHWMPnetDiameterTraversalTime; - struct dentry *dot11MeshHWMPmaxPREQretries; - struct dentry *path_refresh_time; - struct dentry *min_discovery_timeout; - } mesh_config; -#endif - + } debugfs; #endif /* must be last, dynamically sized area in this! */ struct ieee80211_vif vif; @@ -818,53 +755,6 @@ struct ieee80211_local { #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *rcdir; - struct dentry *rcname; - struct dentry *frequency; - struct dentry *total_ps_buffered; - struct dentry *wep_iv; - struct dentry *tsf; - struct dentry *queues; - struct dentry *reset; - struct dentry *noack; - struct dentry *statistics; - struct local_debugfsdentries_statsdentries { - struct dentry *transmitted_fragment_count; - struct dentry *multicast_transmitted_frame_count; - struct dentry *failed_count; - struct dentry *retry_count; - struct dentry *multiple_retry_count; - struct dentry *frame_duplicate_count; - struct dentry *received_fragment_count; - struct dentry *multicast_received_frame_count; - struct dentry *transmitted_frame_count; - struct dentry *wep_undecryptable_count; - struct dentry *num_scans; -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - struct dentry *tx_handlers_drop; - struct dentry *tx_handlers_queued; - struct dentry *tx_handlers_drop_unencrypted; - struct dentry *tx_handlers_drop_fragment; - struct dentry *tx_handlers_drop_wep; - struct dentry *tx_handlers_drop_not_assoc; - struct dentry *tx_handlers_drop_unauth_port; - struct dentry *rx_handlers_drop; - struct dentry *rx_handlers_queued; - struct dentry *rx_handlers_drop_nullfunc; - struct dentry *rx_handlers_drop_defrag; - struct dentry *rx_handlers_drop_short; - struct dentry *rx_handlers_drop_passive_scan; - struct dentry *tx_expand_skb_head; - struct dentry *tx_expand_skb_head_cloned; - struct dentry *rx_expand_skb_head; - struct dentry *rx_expand_skb_head2; - struct dentry *rx_handlers_fragments; - struct dentry *tx_status_drop; -#endif - struct dentry *dot11ACKFailureCount; - struct dentry *dot11RTSFailureCount; - struct dentry *dot11FCSErrorCount; - struct dentry *dot11RTSSuccessCount; - } stats; struct dentry *stations; struct dentry *keys; } debugfs; diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 9572e00f532..a49f93b79e9 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -118,18 +118,6 @@ struct ieee80211_key { struct { struct dentry *stalink; struct dentry *dir; - struct dentry *keylen; - struct dentry *flags; - struct dentry *keyidx; - struct dentry *hw_key_idx; - struct dentry *tx_rx_count; - struct dentry *algorithm; - struct dentry *tx_spec; - struct dentry *rx_spec; - struct dentry *replays; - struct dentry *icverrors; - struct dentry *key; - struct dentry *ifindex; int cnt; } debugfs; #endif diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 797f53942e5..4e80213d6c7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -923,7 +923,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_wep: sta_info_stop(local); fail_sta_info: - debugfs_hw_del(local); destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); @@ -959,7 +958,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); - debugfs_hw_del(local); if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b33efc4fc26..ccda7454fb1 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -163,8 +163,7 @@ struct rate_control_ref *rate_control_alloc(const char *name, #ifdef CONFIG_MAC80211_DEBUGFS debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir); local->debugfs.rcdir = debugfsdir; - local->debugfs.rcname = debugfs_create_file("name", 0400, debugfsdir, - ref, &rcname_ops); + debugfs_create_file("name", 0400, debugfsdir, ref, &rcname_ops); #endif ref->priv = ref->ops->alloc(&local->hw, debugfsdir); @@ -188,9 +187,7 @@ static void rate_control_release(struct kref *kref) ctrl_ref->ops->free(ctrl_ref->priv); #ifdef CONFIG_MAC80211_DEBUGFS - debugfs_remove(ctrl_ref->local->debugfs.rcname); - ctrl_ref->local->debugfs.rcname = NULL; - debugfs_remove(ctrl_ref->local->debugfs.rcdir); + debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir); ctrl_ref->local->debugfs.rcdir = NULL; #endif diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ccc3adf962c..b3686c870b5 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -301,28 +301,6 @@ struct sta_info { #ifdef CONFIG_MAC80211_DEBUGFS struct sta_info_debugfsdentries { struct dentry *dir; - struct dentry *flags; - struct dentry *num_ps_buf_frames; - struct dentry *inactive_ms; - struct dentry *last_seq_ctrl; - struct dentry *agg_status; - struct dentry *aid; - struct dentry *dev; - struct dentry *rx_packets; - struct dentry *tx_packets; - struct dentry *rx_bytes; - struct dentry *tx_bytes; - struct dentry *rx_duplicates; - struct dentry *rx_fragments; - struct dentry *rx_dropped; - struct dentry *tx_fragments; - struct dentry *tx_filtered; - struct dentry *tx_retry_failed; - struct dentry *tx_retry_count; - struct dentry *last_signal; - struct dentry *last_qual; - struct dentry *last_noise; - struct dentry *wep_weak_iv_count; bool add_has_run; } debugfs; #endif diff --git a/net/wireless/core.c b/net/wireless/core.c index 07252967be9..02835172b22 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -546,7 +546,7 @@ void wiphy_unregister(struct wiphy *wiphy) * First remove the hardware from everywhere, this makes * it impossible to find from userspace. */ - cfg80211_debugfs_rdev_del(rdev); + debugfs_remove_recursive(rdev->wiphy.debugfsdir); list_del(&rdev->list); /* @@ -569,7 +569,6 @@ void wiphy_unregister(struct wiphy *wiphy) cfg80211_rdev_list_generation++; device_del(&rdev->wiphy.dev); - debugfs_remove(rdev->wiphy.debugfsdir); mutex_unlock(&cfg80211_mutex); diff --git a/net/wireless/core.h b/net/wireless/core.h index 68b321997d4..5aeebb9085f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -72,17 +72,6 @@ struct cfg80211_registered_device { /* current channel */ struct ieee80211_channel *channel; -#ifdef CONFIG_CFG80211_DEBUGFS - /* Debugfs entries */ - struct wiphy_debugfsdentries { - struct dentry *rts_threshold; - struct dentry *fragmentation_threshold; - struct dentry *short_retry_limit; - struct dentry *long_retry_limit; - struct dentry *ht40allow_map; - } debugfs; -#endif - /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index 13d93d84f90..2e489561503 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c @@ -104,11 +104,7 @@ static const struct file_operations ht40allow_map_ops = { }; #define DEBUGFS_ADD(name) \ - rdev->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ - &rdev->wiphy, &name## _ops); -#define DEBUGFS_DEL(name) \ - debugfs_remove(rdev->debugfs.name); \ - rdev->debugfs.name = NULL; + debugfs_create_file(#name, S_IRUGO, phyd, &rdev->wiphy, &name## _ops); void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) { @@ -120,12 +116,3 @@ void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) DEBUGFS_ADD(long_retry_limit); DEBUGFS_ADD(ht40allow_map); } - -void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev) -{ - DEBUGFS_DEL(rts_threshold); - DEBUGFS_DEL(fragmentation_threshold); - DEBUGFS_DEL(short_retry_limit); - DEBUGFS_DEL(long_retry_limit); - DEBUGFS_DEL(ht40allow_map); -} diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h index 6419b6d6ce3..74fdd381142 100644 --- a/net/wireless/debugfs.h +++ b/net/wireless/debugfs.h @@ -3,12 +3,9 @@ #ifdef CONFIG_CFG80211_DEBUGFS void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev); -void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev); #else static inline void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {} -static inline -void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev) {} #endif #endif /* __CFG80211_DEBUGFS_H */ -- cgit v1.2.3 From ed620590de15021f6baf08ca098c90f47470efd7 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 27 Oct 2009 17:36:09 +0200 Subject: mac80211: refactor dynamic power save check Refactor dynamic power save checks to a function of it's own for better readibility. No functional changes. Signed-off-by: Kalle Valo Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index eaa4118de98..498cdd435d7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1387,6 +1387,26 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, return 0; } +static bool need_dynamic_ps(struct ieee80211_local *local) +{ + /* driver doesn't support power save */ + if (!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) + return false; + + /* dynamic power save disabled */ + if (local->hw.conf.dynamic_ps_timeout <= 0) + return false; + + /* we are scanning, don't enable power save */ + if (local->scanning) + return false; + + if (!local->ps_sdata) + return false; + + return true; +} + static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -1399,9 +1419,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_hold(sdata->dev); - if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && - local->hw.conf.dynamic_ps_timeout > 0 && - !(local->scanning) && local->ps_sdata) { + if (need_dynamic_ps(local)) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); -- cgit v1.2.3 From a9685338ab9d331c25ca92b0e8a92631e14c6b45 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 27 Oct 2009 17:36:17 +0200 Subject: mac80211: fix dynamic power save for devices with nullfunc support in hw In TX path it was assumed that dynamic power save works only if IEEE80211_HW_PS_NULLFUNC_STACK is set. But is not the case, there are devices which have nullfunc support in hardware but need mac80211 to handle dynamic power save timers, TI's wl1251 is one of them. The fix is to not check for IEEE80211_HW_PS_NULLFUNC_STACK in is_dynamic_ps_enabled(), instead check IEEE80211_HW_SUPPORTS_PS and IEEE80211_HW_SUPPORTS_DYNAMIC_PS flags and act accordingly. Tested with wl1251. Signed-off-by: Kalle Valo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 498cdd435d7..cb06d8e5649 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1390,7 +1390,11 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, static bool need_dynamic_ps(struct ieee80211_local *local) { /* driver doesn't support power save */ - if (!(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) + return false; + + /* hardware does dynamic power save */ + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) return false; /* dynamic power save disabled */ -- cgit v1.2.3 From b59f04cbf8ab4dce63f0d2ed658624b0ad21c67d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 27 Oct 2009 20:56:21 +0100 Subject: mac80211: remove outdated comment This comment hasn't been a real TODO item for a long time now since we fixed that quite a while ago. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 7a350d2690a..1a643fe5250 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -12,8 +12,6 @@ * published by the Free Software Foundation. */ -/* TODO: figure out how to avoid that the "current BSS" expires */ - #include #include #include -- cgit v1.2.3 From 4d36ec58239eec44d77839ef6c25108efcbbb58c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 27 Oct 2009 20:59:55 +0100 Subject: mac80211: split hardware scan by band There's currently a very odd bug in mac80211 -- a hardware scan that is done while the hardware is really operating on 2.4 GHz will include CCK rates in the probe request frame, even on 5 GHz (if the driver uses the mac80211 IEs). Vice versa, if the hardware is operating on 5 GHz the 2.4 GHz probe requests will not include CCK rates even though they should. Fix this by splitting up cfg80211 scan requests by band -- recalculating the IEs every time -- and requesting only per-band scans from the driver. Apparently this bug hasn't been a problem yet, but it is imaginable that some older access points get confused if confronted with such behaviour. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 8 ++-- net/mac80211/scan.c | 96 ++++++++++++++++++++++++++++++++++------------ net/mac80211/util.c | 8 ++-- 3 files changed, 80 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 60c2822802f..6365079e637 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -667,10 +667,9 @@ struct ieee80211_local { unsigned long scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request *int_scan_req; - struct cfg80211_scan_request *scan_req; + struct cfg80211_scan_request *scan_req, *hw_scan_req; struct ieee80211_channel *scan_channel; - const u8 *orig_ies; - int orig_ies_len; + enum ieee80211_band hw_scan_band; int scan_channel_idx; int scan_ies_len; @@ -1050,7 +1049,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u8 *extra, size_t extra_len, const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - const u8 *ie, size_t ie_len); + const u8 *ie, size_t ie_len, + enum ieee80211_band band); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1a643fe5250..c46ac01e2a8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -187,6 +187,39 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) return RX_QUEUED; } +/* return false if no more work */ +static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) +{ + struct cfg80211_scan_request *req = local->scan_req; + enum ieee80211_band band; + int i, ielen, n_chans; + + do { + if (local->hw_scan_band == IEEE80211_NUM_BANDS) + return false; + + band = local->hw_scan_band; + n_chans = 0; + for (i = 0; i < req->n_channels; i++) { + if (req->channels[i]->band == band) { + local->hw_scan_req->channels[n_chans] = + req->channels[i]; + n_chans++; + } + } + + local->hw_scan_band++; + } while (!n_chans); + + local->hw_scan_req->n_channels = n_chans; + + ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, + req->ie, req->ie_len, band); + local->hw_scan_req->ie_len = ielen; + + return true; +} + /* * inform AP that we will go to sleep so that it will buffer the frames * while we scan @@ -247,13 +280,6 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) } } -static void ieee80211_restore_scan_ies(struct ieee80211_local *local) -{ - kfree(local->scan_req->ie); - local->scan_req->ie = local->orig_ies; - local->scan_req->ie_len = local->orig_ies_len; -} - void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); @@ -272,15 +298,22 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) return; } - if (test_bit(SCAN_HW_SCANNING, &local->scanning)) - ieee80211_restore_scan_ies(local); + was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); + if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, 0); + mutex_unlock(&local->scan_mtx); + return; + } + + kfree(local->hw_scan_req); + local->hw_scan_req = NULL; if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; local->scan_sdata = NULL; - was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); local->scanning = 0; local->scan_channel = NULL; @@ -392,19 +425,23 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->ops->hw_scan) { u8 *ies; - int ielen; - ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + req->ie_len, GFP_KERNEL); - if (!ies) + local->hw_scan_req = kmalloc( + sizeof(*local->hw_scan_req) + + req->n_channels * sizeof(req->channels[0]) + + 2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + + req->ie_len, GFP_KERNEL); + if (!local->hw_scan_req) return -ENOMEM; - ielen = ieee80211_build_preq_ies(local, ies, - req->ie, req->ie_len); - local->orig_ies = req->ie; - local->orig_ies_len = req->ie_len; - req->ie = ies; - req->ie_len = ielen; + local->hw_scan_req->ssids = req->ssids; + local->hw_scan_req->n_ssids = req->n_ssids; + ies = (u8 *)local->hw_scan_req + + sizeof(*local->hw_scan_req) + + req->n_channels * sizeof(req->channels[0]); + local->hw_scan_req->ie = ies; + + local->hw_scan_band = 0; } local->scan_req = req; @@ -436,16 +473,17 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(local); mutex_unlock(&local->scan_mtx); - if (local->ops->hw_scan) - rc = drv_hw_scan(local, local->scan_req); - else + if (local->ops->hw_scan) { + WARN_ON(!ieee80211_prep_hw_scan(local)); + rc = drv_hw_scan(local, local->hw_scan_req); + } else rc = ieee80211_start_sw_scan(local); mutex_lock(&local->scan_mtx); if (rc) { - if (local->ops->hw_scan) - ieee80211_restore_scan_ies(local); + kfree(local->hw_scan_req); + local->hw_scan_req = NULL; local->scanning = 0; ieee80211_recalc_idle(local); @@ -654,6 +692,14 @@ void ieee80211_scan_work(struct work_struct *work) return; } + if (local->hw_scan_req) { + int rc = drv_hw_scan(local, local->hw_scan_req); + mutex_unlock(&local->scan_mtx); + if (rc) + ieee80211_scan_completed(&local->hw, true); + return; + } + if (local->scan_req && !local->scanning) { struct cfg80211_scan_request *req = local->scan_req; int rc; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aeb65b3d229..aedbaaa067e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -872,13 +872,14 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, } int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, + enum ieee80211_band band) { struct ieee80211_supported_band *sband; u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; int i; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; pos = buffer; @@ -966,7 +967,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, memcpy(pos, ssid, ssid_len); pos += ssid_len; - skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); + skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, + local->hw.conf.channel->band)); ieee80211_tx_skb(sdata, skb, 0); } -- cgit v1.2.3 From 6a86b9c78ebd0397eb953493c68ea9e194e7023c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Oct 2009 09:58:52 +0100 Subject: mac80211: fix radiotap header generation In commit 601ae7f25aea58f208a7f640f6174aac0652403a Author: Bruno Randolf Date: Thu May 8 19:22:43 2008 +0200 mac80211: make rx radiotap header more flexible code was added that tried to align the radiotap header position in memory based on the radiotap header length. Quite obviously, that is completely useless. Instead of trying to do that, use unaligned accesses to generate the radiotap header. To properly do that, we also need to mark struct ieee80211_radiotap_header packed, but that is fine since it's already packed (and it should be marked packed anyway since its a wire format). Cc: Bruno Randolf Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/ieee80211_radiotap.h | 2 +- net/mac80211/rx.c | 26 ++++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index 23c3f3d9777..9d3d86aaccb 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -80,7 +80,7 @@ struct ieee80211_radiotap_header { * Additional extensions are made * by setting bit 31. */ -}; +} __packed; /* Name Data type Units * ---- --------- ----- diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5c385e3c1d1..01df328530a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -95,10 +95,6 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, if (len & 1) /* padding for RX_FLAGS if necessary */ len++; - /* make sure radiotap starts at a naturally aligned address */ - if (len % 8) - len = roundup(len, 8); - return len; } @@ -116,6 +112,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_header *rthdr; unsigned char *pos; + u16 rx_flags = 0; rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); memset(rthdr, 0, rtap_len); @@ -134,7 +131,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* IEEE80211_RADIOTAP_TSFT */ if (status->flag & RX_FLAG_TSFT) { - *(__le64 *)pos = cpu_to_le64(status->mactime); + put_unaligned_le64(status->mactime, pos); rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); pos += 8; @@ -166,17 +163,17 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos++; /* IEEE80211_RADIOTAP_CHANNEL */ - *(__le16 *)pos = cpu_to_le16(status->freq); + put_unaligned_le16(status->freq, pos); pos += 2; if (status->band == IEEE80211_BAND_5GHZ) - *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ); + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, + pos); else if (rate->flags & IEEE80211_RATE_ERP_G) - *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ); + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, + pos); else - *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ); + put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, + pos); pos += 2; /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ @@ -205,10 +202,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* IEEE80211_RADIOTAP_RX_FLAGS */ /* ensure 2 byte alignment for the 2 byte field as required */ - if ((pos - (unsigned char *)rthdr) & 1) + if ((pos - (u8 *)rthdr) & 1) pos++; if (status->flag & RX_FLAG_FAILED_PLCP_CRC) - *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADPLCP); + rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; + put_unaligned_le16(rx_flags, pos); pos += 2; } -- cgit v1.2.3 From 0869aea0eb711982cd2b8bebf41b3c0191c89cde Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Oct 2009 10:03:35 +0100 Subject: mac80211: remove RX_FLAG_RADIOTAP While there may be a case for a driver adding its own bits of radiotap information, none currently does. Also, drivers would have to copy the code to generate the radiotap bits that now mac80211 generates. If some driver in the future needs to add some driver-specific information I'd expect that to be in a radiotap vendor namespace and we can add a different way of passing such data up and having mac80211 include it. Additionally, rename IEEE80211_CONF_RADIOTAP to IEEE80211_CONF_MONITOR since it's still used by b43(legacy) to obtain per-frame timestamps. The purpose of this patch is to simplify the RX code in mac80211 to make it easier to add paged skb support. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43legacy/main.c | 2 +- include/net/mac80211.h | 15 +++++++-------- net/mac80211/iface.c | 8 ++++---- net/mac80211/rx.c | 33 ++++++++++++--------------------- 5 files changed, 25 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ed6e96a3474..c806924c7b5 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3573,7 +3573,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (conf->channel->hw_value != phy->channel) b43_switch_channel(dev, conf->channel->hw_value); - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR); /* Adjust the desired TX power level. */ if (conf->power_level != 0) { diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 0983406f463..d579bb9035c 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2676,7 +2676,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, if (conf->channel->hw_value != phy->channel) b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0); - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR); /* Adjust the desired TX power level. */ if (conf->power_level != 0) { diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c42c4a820b8..2c9d3c719d8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -494,7 +494,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame. * Use together with %RX_FLAG_MMIC_STRIPPED. * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. - * @RX_FLAG_RADIOTAP: This frame starts with a radiotap header. * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, * verification has been done by the hardware. * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. @@ -515,7 +514,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, RX_FLAG_DECRYPTED = 1<<1, - RX_FLAG_RADIOTAP = 1<<2, RX_FLAG_MMIC_STRIPPED = 1<<3, RX_FLAG_IV_STRIPPED = 1<<4, RX_FLAG_FAILED_FCS_CRC = 1<<5, @@ -565,7 +563,9 @@ struct ieee80211_rx_status { * * Flags to define PHY configuration options * - * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) + * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this + * to determine for example whether to calculate timestamps for packets + * or not, do not use instead of filter flags! * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only) * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set * the driver should be prepared to handle configuration requests but @@ -574,7 +574,7 @@ struct ieee80211_rx_status { * it can also be unset in that case when monitor interfaces are active. */ enum ieee80211_conf_flags { - IEEE80211_CONF_RADIOTAP = (1<<0), + IEEE80211_CONF_MONITOR = (1<<0), IEEE80211_CONF_PS = (1<<1), IEEE80211_CONF_IDLE = (1<<2), }; @@ -584,7 +584,7 @@ enum ieee80211_conf_flags { * enum ieee80211_conf_changed - denotes which configuration changed * * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed - * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed + * @IEEE80211_CONF_CHANGE_MONITOR: the monitor flag changed * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed * @IEEE80211_CONF_CHANGE_POWER: the TX power changed * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed @@ -593,7 +593,7 @@ enum ieee80211_conf_flags { */ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), - IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), + IEEE80211_CONF_CHANGE_MONITOR = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), IEEE80211_CONF_CHANGE_POWER = BIT(5), IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), @@ -1661,8 +1661,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw); * ieee80211_rx - receive frame * * Use this function to hand received frames to mac80211. The receive - * buffer in @skb must start with an IEEE 802.11 header or a radiotap - * header if %RX_FLAG_RADIOTAP is set in the @status flags. + * buffer in @skb must start with an IEEE 802.11 header. * * This function may not be called in IRQ context. Calls to this function * for a single hardware must be synchronized against each other. Calls to diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 14f10eb91c5..8495161b99b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -214,8 +214,8 @@ static int ieee80211_open(struct net_device *dev) /* must be before the call to ieee80211_configure_filter */ local->monitors++; if (local->monitors == 1) { - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + local->hw.conf.flags |= IEEE80211_CONF_MONITOR; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) @@ -435,8 +435,8 @@ static int ieee80211_stop(struct net_device *dev) local->monitors--; if (local->monitors == 0) { - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 01df328530a..798fa82b6ae 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -39,11 +39,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, * only useful for monitoring. */ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, - struct sk_buff *skb, - int rtap_len) + struct sk_buff *skb) { - skb_pull(skb, rtap_len); - if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { if (likely(skb->len > FCS_LEN)) skb_trim(skb, skb->len - FCS_LEN); @@ -59,15 +56,14 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, } static inline int should_drop_frame(struct sk_buff *skb, - int present_fcs_len, - int radiotap_len) + int present_fcs_len) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) return 1; - if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) + if (unlikely(skb->len < 16 + present_fcs_len)) return 1; if (ieee80211_is_ctl(hdr->frame_control) && !ieee80211_is_pspoll(hdr->frame_control) && @@ -225,7 +221,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, struct sk_buff *skb, *skb2; struct net_device *prev_dev = NULL; int present_fcs_len = 0; - int rtap_len = 0; /* * First, we may need to make a copy of the skb because @@ -235,25 +230,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, * We don't need to, of course, if we aren't going to return * the SKB because it has a bad FCS/PLCP checksum. */ - if (status->flag & RX_FLAG_RADIOTAP) - rtap_len = ieee80211_get_radiotap_len(origskb->data); - else - /* room for the radiotap header based on driver features */ - needed_headroom = ieee80211_rx_radiotap_len(local, status); + + /* room for the radiotap header based on driver features */ + needed_headroom = ieee80211_rx_radiotap_len(local, status); if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; if (!local->monitors) { - if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len)) { dev_kfree_skb(origskb); return NULL; } - return remove_monitor_info(local, origskb, rtap_len); + return remove_monitor_info(local, origskb); } - if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len)) { /* only need to expand headroom if necessary */ skb = origskb; origskb = NULL; @@ -277,16 +270,14 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, */ skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); - origskb = remove_monitor_info(local, origskb, rtap_len); + origskb = remove_monitor_info(local, origskb); if (!skb) return origskb; } - /* if necessary, prepend radiotap information */ - if (!(status->flag & RX_FLAG_RADIOTAP)) - ieee80211_add_rx_radiotap_header(local, skb, rate, - needed_headroom); + /* prepend radiotap information */ + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; -- cgit v1.2.3 From 8ce0b5892460c670b71b7a0bf96549f5e7a63d6c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 28 Oct 2009 13:13:52 -0700 Subject: mac80211: make align adjustment code support paged SKB This fixed a BUG_ON in __skb_trim() when paged rx is used in iwlwifi driver. Yes, the whole mac80211 stack doesn't support paged SKB yet. But let's start the work slowly from small code snippets. Reported-and-tested-by: Abhijeet Kolekar Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- net/mac80211/rx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 798fa82b6ae..c832d408187 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1326,10 +1326,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) skb = NULL; } else { u8 *data = skb->data; - size_t len = skb->len; - u8 *new = __skb_push(skb, align); - memmove(new, data, len); - __skb_trim(skb, len); + size_t len = skb_headlen(skb); + skb->data -= align; + memmove(skb->data, data, len); + skb_set_tail_pointer(skb, len); } } #endif -- cgit v1.2.3 From eddcbb94f75c3e8944503e9f13c1d29acd0d7052 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 08:30:35 +0100 Subject: mac80211: introduce ieee80211_beacon_get_tim() Compared to ieee80211_beacon_get(), the new function ieee80211_beacon_get_tim() returns information on the location and length of the TIM IE, which some drivers need in order to generate the TIM on the device. The old function, ieee80211_beacon_get(), becomes a small static inline wrapper around the new one to not break all drivers. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 42 ++++++++++++++++++++++++++++++++++-------- net/mac80211/tx.c | 17 ++++++++++++++--- 2 files changed, 48 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2c9d3c719d8..bd0bbc37a1a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1743,19 +1743,45 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); /** - * ieee80211_beacon_get - beacon generation function + * ieee80211_beacon_get_tim - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @tim_offset: pointer to variable that will receive the TIM IE offset. + * Set to 0 if invalid (in non-AP modes). + * @tim_length: pointer to variable that will receive the TIM IE length, + * (including the ID and length bytes!). + * Set to 0 if invalid (in non-AP modes). + * + * If the driver implements beaconing modes, it must use this function to + * obtain the beacon frame/template. * * If the beacon frames are generated by the host system (i.e., not in - * hardware/firmware), the low-level driver uses this function to receive - * the next beacon frame from the 802.11 code. The low-level is responsible - * for calling this function before beacon data is needed (e.g., based on - * hardware interrupt). Returned skb is used only once and low-level driver - * is responsible for freeing it. + * hardware/firmware), the driver uses this function to get each beacon + * frame from mac80211 -- it is responsible for calling this function + * before the beacon is needed (e.g. based on hardware interrupt). + * + * If the beacon frames are generated by the device, then the driver + * must use the returned beacon as the template and change the TIM IE + * according to the current DTIM parameters/TIM bitmap. + * + * The driver is responsible for freeing the returned skb. + */ +struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 *tim_offset, u16 *tim_length); + +/** + * ieee80211_beacon_get - beacon generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * + * See ieee80211_beacon_get_tim(). */ -struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); +static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); +} /** * ieee80211_rts_get - RTS frame generation function diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cb06d8e5649..8595d14c774 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2012,8 +2012,9 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, } } -struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 *tim_offset, u16 *tim_length) { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb = NULL; @@ -2030,6 +2031,11 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); + if (tim_offset) + *tim_offset = 0; + if (tim_length) + *tim_length = 0; + if (sdata->vif.type == NL80211_IFTYPE_AP) { ap = &sdata->u.ap; beacon = rcu_dereference(ap->beacon); @@ -2065,6 +2071,11 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, spin_unlock_irqrestore(&local->sta_lock, flags); } + if (tim_offset) + *tim_offset = beacon->head_len; + if (tim_length) + *tim_length = skb->len - beacon->head_len; + if (beacon->tail) memcpy(skb_put(skb, beacon->tail_len), beacon->tail, beacon->tail_len); @@ -2141,7 +2152,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, rcu_read_unlock(); return skb; } -EXPORT_SYMBOL(ieee80211_beacon_get); +EXPORT_SYMBOL(ieee80211_beacon_get_tim); void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, -- cgit v1.2.3 From c27f2fded51948edf40007f4f31350e9e0c6ba23 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 08:41:25 +0100 Subject: mac80211: deprecate qual value This value is unused by mac80211, because it was only be used by wireless extensions, and turned out to not be useful there because the quality value needs to be comparable between scan results and the current value which is impossible when the qual value is calculated taking into account noise, for example. Since it is unused anyway, this patch deprecates it in the hope that drivers will remove their sometimes quite expensive calculations of the value. I'm open to actual uses of the value, but the best way of using it seems to be what the Intel drivers do which should probably be generalised if we have noise values from the hardware. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 2 +- net/mac80211/debugfs_sta.c | 2 -- net/mac80211/rx.c | 1 - net/mac80211/sta_info.h | 2 -- 4 files changed, 1 insertion(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index bd0bbc37a1a..e12293e60ac 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -552,7 +552,7 @@ struct ieee80211_rx_status { int freq; int signal; int noise; - int qual; + int __deprecated qual; int antenna; int rate_idx; int flag; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 8721679773d..4425b613552 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -57,7 +57,6 @@ STA_FILE(tx_filtered, tx_filtered_count, LU); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); STA_FILE(last_signal, last_signal, D); -STA_FILE(last_qual, last_qual, D); STA_FILE(last_noise, last_noise, D); STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); @@ -205,7 +204,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(tx_retry_failed); DEBUGFS_ADD(tx_retry_count); DEBUGFS_ADD(last_signal); - DEBUGFS_ADD(last_qual); DEBUGFS_ADD(last_noise); DEBUGFS_ADD(wep_weak_iv_count); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c832d408187..f862399f7ce 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -859,7 +859,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; sta->last_signal = rx->status->signal; - sta->last_qual = rx->status->qual; sta->last_noise = rx->status->noise; /* diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b3686c870b5..703f5492ee6 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -193,7 +193,6 @@ struct sta_ampdu_mlme { * @rx_fragments: number of received MPDUs * @rx_dropped: number of dropped MPDUs from this STA * @last_signal: signal of last received frame from this STA - * @last_qual: qual of last received frame from this STA * @last_noise: noise of last received frame from this STA * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) * @tx_filtered_count: number of frames the hardware filtered for this STA @@ -259,7 +258,6 @@ struct sta_info { unsigned long rx_fragments; unsigned long rx_dropped; int last_signal; - int last_qual; int last_noise; __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; -- cgit v1.2.3 From 62b517cb3e974624a2958ad0b603ebb59cd96e16 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 12:19:21 +0100 Subject: mac80211: unconditionally set IEEE80211_TX_CTL_SEND_AFTER_DTIM When mac80211 is asked to buffer multicast frames in AP mode, it will not set the flag indicating that the frames should be sent after the DTIM beacon for those frames buffered in software. Fix this little inconsistency by always setting that flag in the buffering code path. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8595d14c774..844609c2326 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -317,12 +317,11 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) if (!atomic_read(&tx->sdata->bss->num_sta_ps)) return TX_CONTINUE; - /* buffered in hardware */ - if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) { - info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + /* device releases frame after DTIM beacon */ + if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) return TX_CONTINUE; - } /* buffered in mac80211 */ if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) -- cgit v1.2.3 From 22403def134e2c1017cb04ae9129a38e841b2d8c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 30 Oct 2009 12:55:03 +0100 Subject: mac80211: also drop qos-nullfunc frames silently We drop nullfunc frames, but not qos-nullfunc frames, even though those could be used for PS state control as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 12 +++++++++++- net/mac80211/rx.c | 15 ++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 52e15e079c6..0aa83146749 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -472,7 +472,7 @@ static inline int ieee80211_is_cfendack(__le16 fc) } /** - * ieee80211_is_nullfunc - check if FTYPE=IEEE80211_FTYPE_DATA and STYPE=IEEE80211_STYPE_NULLFUNC + * ieee80211_is_nullfunc - check if frame is a regular (non-QoS) nullfunc frame * @fc: frame control bytes in little-endian byteorder */ static inline int ieee80211_is_nullfunc(__le16 fc) @@ -481,6 +481,16 @@ static inline int ieee80211_is_nullfunc(__le16 fc) cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC); } +/** + * ieee80211_is_qos_nullfunc - check if frame is a QoS nullfunc frame + * @fc: frame control bytes in little-endian byteorder + */ +static inline int ieee80211_is_qos_nullfunc(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); +} + struct ieee80211s_hdr { u8 flags; u8 ttl; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f862399f7ce..51cb8bc3af8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -886,12 +886,17 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) } } - /* Drop data::nullfunc frames silently, since they are used only to - * control station power saving mode. */ - if (ieee80211_is_nullfunc(hdr->frame_control)) { + /* + * Drop (qos-)data::nullfunc frames silently, since they + * are used only to control station power saving mode. + */ + if (ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); - /* Update counter and free packet here to avoid counting this - * as a dropped packed. */ + /* + * Update counter and free packet here to avoid + * counting this as a dropped packed. + */ sta->rx_packets++; dev_kfree_skb(rx->skb); return RX_QUEUED; -- cgit v1.2.3 From ff9458d3ec179831ebe6966a8aa014ccb3907dc6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 30 Oct 2009 12:56:02 +0100 Subject: mac80211: remove sent_ps_buffered This variable is set once, and tested once. However, the code path that can set it is mutually exclusive with the code path that tests it, so the test is always true. Thus we also don't need to set it either and can just remove the variable. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/rx.c | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6365079e637..1ef767366b7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -176,7 +176,6 @@ struct ieee80211_rx_data { struct ieee80211_rate *rate; unsigned int flags; - int sent_ps_buffered; int queue; u32 tkip_iv32; u16 tkip_iv16; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 51cb8bc3af8..c06496f0b76 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -789,7 +789,7 @@ static void ap_sta_ps_start(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } -static int ap_sta_ps_end(struct sta_info *sta) +static void ap_sta_ps_end(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; @@ -819,8 +819,6 @@ static int ap_sta_ps_end(struct sta_info *sta) "since STA not sleeping anymore\n", sdata->dev->name, sta->sta.addr, sta->sta.aid, sent - buffered, buffered); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - - return sent; } static ieee80211_rx_result debug_noinline @@ -879,7 +877,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) */ if (ieee80211_is_data(hdr->frame_control) && !ieee80211_has_pm(hdr->frame_control)) - rx->sent_ps_buffered += ap_sta_ps_end(sta); + ap_sta_ps_end(sta); } else { if (ieee80211_has_pm(hdr->frame_control)) ap_sta_ps_start(sta); @@ -1147,7 +1145,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) if (no_pending_pkts) sta_info_clear_tim_bit(rx->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - } else if (!rx->sent_ps_buffered) { + } else { /* * FIXME: This can be the result of a race condition between * us expiring a frame and the station polling for it. -- cgit v1.2.3 From e6e898cfea5f35d64f850277e7fa295c386cf953 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 30 Oct 2009 15:48:43 +0100 Subject: mac80211: remove bogus code It's not right to do something here when returning an error, and hostapd should never have relied on it as it only fixes up a small part of the problem anyway. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5608f6c6841..a0c7eb18a76 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -738,13 +738,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, err = sta_info_insert(sta); if (err) { - /* STA has been freed */ - if (err == -EEXIST && layer2_update) { - /* Need to update layer 2 devices on reassociation */ - sta = sta_info_get(local, mac); - if (sta) - ieee80211_send_layer2_update(sta); - } rcu_read_unlock(); return err; } -- cgit v1.2.3 From 244546f0d3101c5441f5b14cfe8a79d62679eaea Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 30 Oct 2009 08:54:53 +0000 Subject: RDS: Add GET_MR_FOR_DEST sockopt RDS currently supports a GET_MR sockopt to establish a memory region (MR) for a chunk of memory. However, the fastreg method ties a MR to a particular destination. The GET_MR_FOR_DEST sockopt allows the remote machine to be specified, and thus support for fastreg (aka FRWRs). Note that this patch does *not* do all of this - it simply implements the new sockopt in terms of the old one, so applications can begin to use the new sockopt in preparation for cutover to FRWRs. Signed-off-by: Andy Grover Signed-off-by: David S. Miller --- include/linux/rds.h | 8 ++++++++ net/rds/af_rds.c | 3 +++ net/rds/rdma.c | 24 ++++++++++++++++++++++++ net/rds/rdma.h | 1 + 4 files changed, 36 insertions(+) (limited to 'net') diff --git a/include/linux/rds.h b/include/linux/rds.h index 89d46e1afbb..cab4994c2f6 100644 --- a/include/linux/rds.h +++ b/include/linux/rds.h @@ -56,6 +56,7 @@ /* deprecated: RDS_BARRIER 4 */ #define RDS_RECVERR 5 #define RDS_CONG_MONITOR 6 +#define RDS_GET_MR_FOR_DEST 7 /* * Control message types for SOL_RDS. @@ -224,6 +225,13 @@ struct rds_get_mr_args { uint64_t flags; }; +struct rds_get_mr_for_dest_args { + struct sockaddr_storage dest_addr; + struct rds_iovec vec; + u_int64_t cookie_addr; + uint64_t flags; +}; + struct rds_free_mr_args { rds_rdma_cookie_t cookie; u_int64_t flags; diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index a202e5b3607..2b978dc6e75 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -265,6 +265,9 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, case RDS_GET_MR: ret = rds_get_mr(rs, optval, optlen); break; + case RDS_GET_MR_FOR_DEST: + ret = rds_get_mr_for_dest(rs, optval, optlen); + break; case RDS_FREE_MR: ret = rds_free_mr(rs, optval, optlen); break; diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 8dc83d2caa5..971b5a66845 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -317,6 +317,30 @@ int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen) return __rds_rdma_map(rs, &args, NULL, NULL); } +int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen) +{ + struct rds_get_mr_for_dest_args args; + struct rds_get_mr_args new_args; + + if (optlen != sizeof(struct rds_get_mr_for_dest_args)) + return -EINVAL; + + if (copy_from_user(&args, (struct rds_get_mr_for_dest_args __user *)optval, + sizeof(struct rds_get_mr_for_dest_args))) + return -EFAULT; + + /* + * Initially, just behave like get_mr(). + * TODO: Implement get_mr as wrapper around this + * and deprecate it. + */ + new_args.vec = args.vec; + new_args.cookie_addr = args.cookie_addr; + new_args.flags = args.flags; + + return __rds_rdma_map(rs, &new_args, NULL, NULL); +} + /* * Free the MR indicated by the given R_Key */ diff --git a/net/rds/rdma.h b/net/rds/rdma.h index 425512098b0..909c39835a5 100644 --- a/net/rds/rdma.h +++ b/net/rds/rdma.h @@ -61,6 +61,7 @@ static inline u32 rds_rdma_cookie_offset(rds_rdma_cookie_t cookie) } int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen); +int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen); int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen); void rds_rdma_drop_keys(struct rds_sock *rs); int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, -- cgit v1.2.3 From 86357b19bcabd9355937f3fb84f90ba9fe76a5d3 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 30 Oct 2009 08:51:54 +0000 Subject: RDS: Fix potential race around rds_i[bw]_allocation "At rds_ib_recv_refill_one(), it first executes atomic_read(&rds_ib_allocation) for if-condition checking, and then executes atomic_inc(&rds_ib_allocation) if the condition was not satisfied. However, if any other code which updates rds_ib_allocation executes between these two atomic operation executions, it seems that it may result race condition. (especially when rds_ib_allocation + 1 == rds_ib_sysctl_max_recv_allocation)" This patch fixes this by using atomic_inc_unless to eliminate the possibility of allocating more than rds_ib_sysctl_max_recv_allocation and then decrementing the count if the allocation fails. It also makes an identical change to the iwarp transport. Reported-by: Shin Hong Signed-off-by: Andy Grover Signed-off-by: David S. Miller --- net/rds/ib_recv.c | 7 ++++--- net/rds/iw_recv.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index cd7a6cfcab0..2f009d391c2 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -143,15 +143,16 @@ static int rds_ib_recv_refill_one(struct rds_connection *conn, int ret = -ENOMEM; if (recv->r_ibinc == NULL) { - if (atomic_read(&rds_ib_allocation) >= rds_ib_sysctl_max_recv_allocation) { + if (!atomic_add_unless(&rds_ib_allocation, 1, rds_ib_sysctl_max_recv_allocation)) { rds_ib_stats_inc(s_ib_rx_alloc_limit); goto out; } recv->r_ibinc = kmem_cache_alloc(rds_ib_incoming_slab, kptr_gfp); - if (recv->r_ibinc == NULL) + if (recv->r_ibinc == NULL) { + atomic_dec(&rds_ib_allocation); goto out; - atomic_inc(&rds_ib_allocation); + } INIT_LIST_HEAD(&recv->r_ibinc->ii_frags); rds_inc_init(&recv->r_ibinc->ii_inc, conn, conn->c_faddr); } diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 8683f5f66c4..9f98150af19 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -143,15 +143,16 @@ static int rds_iw_recv_refill_one(struct rds_connection *conn, int ret = -ENOMEM; if (recv->r_iwinc == NULL) { - if (atomic_read(&rds_iw_allocation) >= rds_iw_sysctl_max_recv_allocation) { + if (!atomic_add_unless(&rds_iw_allocation, 1, rds_iw_sysctl_max_recv_allocation)) { rds_iw_stats_inc(s_iw_rx_alloc_limit); goto out; } recv->r_iwinc = kmem_cache_alloc(rds_iw_incoming_slab, kptr_gfp); - if (recv->r_iwinc == NULL) + if (recv->r_iwinc == NULL) { + atomic_dec(&rds_iw_allocation); goto out; - atomic_inc(&rds_iw_allocation); + } INIT_LIST_HEAD(&recv->r_iwinc->ii_frags); rds_inc_init(&recv->r_iwinc->ii_inc, conn, conn->c_faddr); } -- cgit v1.2.3 From 433d308dd85e506bb6529177cc0f997627d87ed6 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 30 Oct 2009 08:51:55 +0000 Subject: RDS: Fix panic on unload Remove explicit destruction of passive connection when destroying active end of the connection. The passive end is also on the device's connection list, and will thus be cleaned up properly. Panic was caused by trying to clean it up twice. Signed-off-by: Andy Grover Signed-off-by: David S. Miller --- net/rds/ib_rdma.c | 5 +---- net/rds/iw_rdma.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index ef3ab5b7283..c5e916598c1 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -187,11 +187,8 @@ void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock) INIT_LIST_HEAD(list); spin_unlock_irq(list_lock); - list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) { - if (ic->conn->c_passive) - rds_conn_destroy(ic->conn->c_passive); + list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) rds_conn_destroy(ic->conn); - } } struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev) diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c index de4a1b16bf7..b25d785e49f 100644 --- a/net/rds/iw_rdma.c +++ b/net/rds/iw_rdma.c @@ -245,11 +245,8 @@ void __rds_iw_destroy_conns(struct list_head *list, spinlock_t *list_lock) INIT_LIST_HEAD(list); spin_unlock_irq(list_lock); - list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) { - if (ic->conn->c_passive) - rds_conn_destroy(ic->conn->c_passive); + list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) rds_conn_destroy(ic->conn); - } } static void rds_iw_set_scatterlist(struct rds_iw_scatterlist *sg, -- cgit v1.2.3 From 0514f8a9c0cbd26afa70dc56406cc0ee1e134dcf Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 30 Oct 2009 08:51:56 +0000 Subject: RDS: Do not send congestion updates to loopback connections This issue was discovered by HP's Pradeep and fixed in OFED 1.3, but not fixed in later versions, since the fix's implementation was not immediately applyable to the later code. This patch should do the trick for 1.4+ codebases. Signed-off-by: Andy Grover Signed-off-by: David S. Miller --- net/rds/cong.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/rds/cong.c b/net/rds/cong.c index dd2711df640..6d06cac2649 100644 --- a/net/rds/cong.c +++ b/net/rds/cong.c @@ -218,6 +218,8 @@ void rds_cong_queue_updates(struct rds_cong_map *map) spin_lock_irqsave(&rds_cong_lock, flags); list_for_each_entry(conn, &map->m_conn_list, c_map_item) { + if (conn->c_loopback) + continue; if (!test_and_set_bit(0, &conn->c_map_queued)) { rds_stats_inc(s_cong_update_queued); queue_delayed_work(rds_wq, &conn->c_send_w, 0); -- cgit v1.2.3 From d521b63b27e3a397e0ef7ca86b6e813861083c83 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 30 Oct 2009 08:51:57 +0000 Subject: RDS/IB+IW: Move recv processing to a tasklet Move receive processing from event handler to a tasklet. This should help prevent hangcheck timer from going off when RDS is under heavy load. Signed-off-by: Andy Grover Signed-off-by: David S. Miller --- net/rds/ib.h | 2 ++ net/rds/ib_cm.c | 2 ++ net/rds/ib_recv.c | 28 ++++++++++++++++++++++------ net/rds/iw.h | 2 ++ net/rds/iw_cm.c | 2 ++ net/rds/iw_recv.c | 28 ++++++++++++++++++++++------ 6 files changed, 52 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/rds/ib.h b/net/rds/ib.h index 1378b854cac..64df4e79b29 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -98,6 +98,7 @@ struct rds_ib_connection { struct rds_ib_send_work *i_sends; /* rx */ + struct tasklet_struct i_recv_tasklet; struct mutex i_recv_mutex; struct rds_ib_work_ring i_recv_ring; struct rds_ib_incoming *i_ibinc; @@ -303,6 +304,7 @@ void rds_ib_inc_free(struct rds_incoming *inc); int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov, size_t size); void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context); +void rds_ib_recv_tasklet_fn(unsigned long data); void rds_ib_recv_init_ring(struct rds_ib_connection *ic); void rds_ib_recv_clear_ring(struct rds_ib_connection *ic); void rds_ib_recv_init_ack(struct rds_ib_connection *ic); diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index c2d372f13db..9d320692a4f 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -694,6 +694,8 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp) return -ENOMEM; INIT_LIST_HEAD(&ic->ib_node); + tasklet_init(&ic->i_recv_tasklet, rds_ib_recv_tasklet_fn, + (unsigned long) ic); mutex_init(&ic->i_recv_mutex); #ifndef KERNEL_HAS_ATOMIC64 spin_lock_init(&ic->i_ack_lock); diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 2f009d391c2..fe5ab8c6b96 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -825,17 +825,22 @@ void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context) { struct rds_connection *conn = context; struct rds_ib_connection *ic = conn->c_transport_data; - struct ib_wc wc; - struct rds_ib_ack_state state = { 0, }; - struct rds_ib_recv_work *recv; rdsdebug("conn %p cq %p\n", conn, cq); rds_ib_stats_inc(s_ib_rx_cq_call); - ib_req_notify_cq(cq, IB_CQ_SOLICITED); + tasklet_schedule(&ic->i_recv_tasklet); +} - while (ib_poll_cq(cq, 1, &wc) > 0) { +static inline void rds_poll_cq(struct rds_ib_connection *ic, + struct rds_ib_ack_state *state) +{ + struct rds_connection *conn = ic->conn; + struct ib_wc wc; + struct rds_ib_recv_work *recv; + + while (ib_poll_cq(ic->i_recv_cq, 1, &wc) > 0) { rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n", (unsigned long long)wc.wr_id, wc.status, wc.byte_len, be32_to_cpu(wc.ex.imm_data)); @@ -853,7 +858,7 @@ void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context) if (rds_conn_up(conn) || rds_conn_connecting(conn)) { /* We expect errors as the qp is drained during shutdown */ if (wc.status == IB_WC_SUCCESS) { - rds_ib_process_recv(conn, recv, wc.byte_len, &state); + rds_ib_process_recv(conn, recv, wc.byte_len, state); } else { rds_ib_conn_error(conn, "recv completion on " "%pI4 had status %u, disconnecting and " @@ -864,6 +869,17 @@ void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context) rds_ib_ring_free(&ic->i_recv_ring, 1); } +} + +void rds_ib_recv_tasklet_fn(unsigned long data) +{ + struct rds_ib_connection *ic = (struct rds_ib_connection *) data; + struct rds_connection *conn = ic->conn; + struct rds_ib_ack_state state = { 0, }; + + rds_poll_cq(ic, &state); + ib_req_notify_cq(ic->i_recv_cq, IB_CQ_SOLICITED); + rds_poll_cq(ic, &state); if (state.ack_next_valid) rds_ib_set_ack(ic, state.ack_next, state.ack_required); diff --git a/net/rds/iw.h b/net/rds/iw.h index dd72b62bd50..eef2f0c2847 100644 --- a/net/rds/iw.h +++ b/net/rds/iw.h @@ -119,6 +119,7 @@ struct rds_iw_connection { struct rds_iw_send_work *i_sends; /* rx */ + struct tasklet_struct i_recv_tasklet; struct mutex i_recv_mutex; struct rds_iw_work_ring i_recv_ring; struct rds_iw_incoming *i_iwinc; @@ -330,6 +331,7 @@ void rds_iw_inc_free(struct rds_incoming *inc); int rds_iw_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov, size_t size); void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context); +void rds_iw_recv_tasklet_fn(unsigned long data); void rds_iw_recv_init_ring(struct rds_iw_connection *ic); void rds_iw_recv_clear_ring(struct rds_iw_connection *ic); void rds_iw_recv_init_ack(struct rds_iw_connection *ic); diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c index a416b0d492b..394cf6b4d0a 100644 --- a/net/rds/iw_cm.c +++ b/net/rds/iw_cm.c @@ -696,6 +696,8 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp) return -ENOMEM; INIT_LIST_HEAD(&ic->iw_node); + tasklet_init(&ic->i_recv_tasklet, rds_iw_recv_tasklet_fn, + (unsigned long) ic); mutex_init(&ic->i_recv_mutex); #ifndef KERNEL_HAS_ATOMIC64 spin_lock_init(&ic->i_ack_lock); diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 9f98150af19..24fc53f0383 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -784,17 +784,22 @@ void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context) { struct rds_connection *conn = context; struct rds_iw_connection *ic = conn->c_transport_data; - struct ib_wc wc; - struct rds_iw_ack_state state = { 0, }; - struct rds_iw_recv_work *recv; rdsdebug("conn %p cq %p\n", conn, cq); rds_iw_stats_inc(s_iw_rx_cq_call); - ib_req_notify_cq(cq, IB_CQ_SOLICITED); + tasklet_schedule(&ic->i_recv_tasklet); +} - while (ib_poll_cq(cq, 1, &wc) > 0) { +static inline void rds_poll_cq(struct rds_iw_connection *ic, + struct rds_iw_ack_state *state) +{ + struct rds_connection *conn = ic->conn; + struct ib_wc wc; + struct rds_iw_recv_work *recv; + + while (ib_poll_cq(ic->i_recv_cq, 1, &wc) > 0) { rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n", (unsigned long long)wc.wr_id, wc.status, wc.byte_len, be32_to_cpu(wc.ex.imm_data)); @@ -812,7 +817,7 @@ void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context) if (rds_conn_up(conn) || rds_conn_connecting(conn)) { /* We expect errors as the qp is drained during shutdown */ if (wc.status == IB_WC_SUCCESS) { - rds_iw_process_recv(conn, recv, wc.byte_len, &state); + rds_iw_process_recv(conn, recv, wc.byte_len, state); } else { rds_iw_conn_error(conn, "recv completion on " "%pI4 had status %u, disconnecting and " @@ -823,6 +828,17 @@ void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context) rds_iw_ring_free(&ic->i_recv_ring, 1); } +} + +void rds_iw_recv_tasklet_fn(unsigned long data) +{ + struct rds_iw_connection *ic = (struct rds_iw_connection *) data; + struct rds_connection *conn = ic->conn; + struct rds_iw_ack_state state = { 0, }; + + rds_poll_cq(ic, &state); + ib_req_notify_cq(ic->i_recv_cq, IB_CQ_SOLICITED); + rds_poll_cq(ic, &state); if (state.ack_next_valid) rds_iw_set_ack(ic, state.ack_next, state.ack_required); -- cgit v1.2.3 From 72c9528bab94cc052d00ce241b8e85f5d71e45f0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 30 Oct 2009 07:11:27 +0000 Subject: net: Introduce dev_get_by_name_rcu() Some workloads hit dev_base_lock rwlock pretty hard. We can use RCU lookups to avoid touching this rwlock (and avoid touching netdevice refcount) netdevices are already freed after a RCU grace period, so this patch adds no penalty at device dismantle time. However, it adds a synchronize_rcu() call in dev_change_name() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + net/core/dev.c | 49 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e5ece8dceaa..bcf1083857f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1115,6 +1115,7 @@ extern void __dev_remove_pack(struct packet_type *pt); extern struct net_device *dev_get_by_flags(struct net *net, unsigned short flags, unsigned short mask); extern struct net_device *dev_get_by_name(struct net *net, const char *name); +extern struct net_device *dev_get_by_name_rcu(struct net *net, const char *name); extern struct net_device *__dev_get_by_name(struct net *net, const char *name); extern int dev_alloc_name(struct net_device *dev, const char *name); extern int dev_open(struct net_device *dev); diff --git a/net/core/dev.c b/net/core/dev.c index 94f42a15fff..f54d8b8a434 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -213,7 +213,7 @@ static int list_netdevice(struct net_device *dev) write_lock_bh(&dev_base_lock); list_add_tail(&dev->dev_list, &net->dev_base_head); - hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); + hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); hlist_add_head_rcu(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); write_unlock_bh(&dev_base_lock); @@ -230,7 +230,7 @@ static void unlist_netdevice(struct net_device *dev) /* Unlink dev from the device chain */ write_lock_bh(&dev_base_lock); list_del(&dev->dev_list); - hlist_del(&dev->name_hlist); + hlist_del_rcu(&dev->name_hlist); hlist_del_rcu(&dev->index_hlist); write_unlock_bh(&dev_base_lock); } @@ -598,6 +598,32 @@ struct net_device *__dev_get_by_name(struct net *net, const char *name) } EXPORT_SYMBOL(__dev_get_by_name); +/** + * dev_get_by_name_rcu - find a device by its name + * @net: the applicable net namespace + * @name: name to find + * + * Find an interface by name. + * If the name is found a pointer to the device is returned. + * If the name is not found then %NULL is returned. + * The reference counters are not incremented so the caller must be + * careful with locks. The caller must hold RCU lock. + */ + +struct net_device *dev_get_by_name_rcu(struct net *net, const char *name) +{ + struct hlist_node *p; + struct net_device *dev; + struct hlist_head *head = dev_name_hash(net, name); + + hlist_for_each_entry_rcu(dev, p, head, name_hlist) + if (!strncmp(dev->name, name, IFNAMSIZ)) + return dev; + + return NULL; +} +EXPORT_SYMBOL(dev_get_by_name_rcu); + /** * dev_get_by_name - find a device by its name * @net: the applicable net namespace @@ -614,11 +640,11 @@ struct net_device *dev_get_by_name(struct net *net, const char *name) { struct net_device *dev; - read_lock(&dev_base_lock); - dev = __dev_get_by_name(net, name); + rcu_read_lock(); + dev = dev_get_by_name_rcu(net, name); if (dev) dev_hold(dev); - read_unlock(&dev_base_lock); + rcu_read_unlock(); return dev; } EXPORT_SYMBOL(dev_get_by_name); @@ -960,7 +986,12 @@ rollback: write_lock_bh(&dev_base_lock); hlist_del(&dev->name_hlist); - hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); + write_unlock_bh(&dev_base_lock); + + synchronize_rcu(); + + write_lock_bh(&dev_base_lock); + hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); write_unlock_bh(&dev_base_lock); ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); @@ -1062,9 +1093,9 @@ void dev_load(struct net *net, const char *name) { struct net_device *dev; - read_lock(&dev_base_lock); - dev = __dev_get_by_name(net, name); - read_unlock(&dev_base_lock); + rcu_read_lock(); + dev = dev_get_by_name_rcu(net, name); + rcu_read_unlock(); if (!dev && capable(CAP_NET_ADMIN)) request_module("%s", name); -- cgit v1.2.3 From 9fdce099bb72df534daa6193318feaec177998fc Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 30 Oct 2009 14:51:13 +0000 Subject: veth: Fix unregister_netdevice_queue for veth I tested the recent unregister many changes and got a weird, nasty and seemingly unrelasted kernel oops. Changing unregister_netdevice_queue to use list_move_tail fixes the problem for me. ip link add type veth rmmod veth ls /sys/class/net/ showed one of the veth devices still present. A subsequent ip link oopsed the box. Signed-off-by: "Eric W. Biederman" Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index f54d8b8a434..3c40d545a03 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5258,6 +5258,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, netdev_init_queues(dev); INIT_LIST_HEAD(&dev->napi_list); + INIT_LIST_HEAD(&dev->unreg_list); dev->priv_flags = IFF_XMIT_DST_RELEASE; setup(dev); strcpy(dev->name, name); @@ -5339,7 +5340,7 @@ void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) ASSERT_RTNL(); if (head) { - list_add_tail(&dev->unreg_list, head); + list_move_tail(&dev->unreg_list, head); } else { rollback_registered(dev); /* Finish processing unregister after unlock */ -- cgit v1.2.3 From c148fc2e30c988f7e3ac91738b2c03f1cef44849 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 1 Nov 2009 19:23:04 +0000 Subject: ipv4: inetdev_by_index() switch to RCU Use dev_get_by_index_rcu() instead of __dev_get_by_index() and dev_base_lock rwlock Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5df2f6a0b0f..ccccaae50b2 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -405,11 +405,12 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex) { struct net_device *dev; struct in_device *in_dev = NULL; - read_lock(&dev_base_lock); - dev = __dev_get_by_index(net, ifindex); + + rcu_read_lock(); + dev = dev_get_by_index_rcu(net, ifindex); if (dev) in_dev = in_dev_get(dev); - read_unlock(&dev_base_lock); + rcu_read_unlock(); return in_dev; } -- cgit v1.2.3 From 685c7944055b9de51ff509719070afae92b3dbe1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 1 Nov 2009 19:31:03 +0000 Subject: icmp: icmp_send() can avoid a dev_put() We can avoid touching device refcount in icmp_send(), using dev_get_by_index_rcu() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 84adb5754c9..fe11f60ce41 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -501,15 +501,16 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) if (!(rt->rt_flags & RTCF_LOCAL)) { struct net_device *dev = NULL; + rcu_read_lock(); if (rt->fl.iif && net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) - dev = dev_get_by_index(net, rt->fl.iif); + dev = dev_get_by_index_rcu(net, rt->fl.iif); - if (dev) { + if (dev) saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); - dev_put(dev); - } else + else saddr = 0; + rcu_read_unlock(); } tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) | -- cgit v1.2.3 From 3710becf8a58a5c6c4e797e3a3c968c161abdb41 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 1 Nov 2009 19:42:09 +0000 Subject: net: RCU locking for simple ioctl() All ioctls() implemented by dev_ifsioc_locked() : SIOCGIFFLAGS, SIOCGIFMETRIC, SIOCGIFMTU, SIOCGIFHWADDR, SIOCGIFSLAVE, SIOCGIFMAP, SIOCGIFINDEX & SIOCGIFTXQLEN can use RCU lock instead of dev_base_lock rwlock Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 3c40d545a03..76a1502efe6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4315,12 +4315,12 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) EXPORT_SYMBOL(dev_set_mac_address); /* - * Perform the SIOCxIFxxx calls, inside read_lock(dev_base_lock) + * Perform the SIOCxIFxxx calls, inside rcu_read_lock() */ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd) { int err; - struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); + struct net_device *dev = dev_get_by_name_rcu(net, ifr->ifr_name); if (!dev) return -ENODEV; @@ -4552,9 +4552,9 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) case SIOCGIFINDEX: case SIOCGIFTXQLEN: dev_load(net, ifr.ifr_name); - read_lock(&dev_base_lock); + rcu_read_lock(); ret = dev_ifsioc_locked(net, &ifr, cmd); - read_unlock(&dev_base_lock); + rcu_read_unlock(); if (!ret) { if (colon) *colon = ':'; -- cgit v1.2.3 From 654d1f8a019dfa06df8355248e1ce222f303b88d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 2 Nov 2009 10:43:32 +0100 Subject: packet: less dev_put() calls - packet_sendmsg_spkt() can use dev_get_by_name_rcu() to avoid touching device refcount. - packet_getname_spkt() & packet_getname() can use dev_get_by_index_rcu() to avoid touching device refcount too. tpacket_snd() & packet_snd() can not use RCU yet because they can sleep when allocating skb. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/packet/af_packet.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 95ef64e4189..91d246d3478 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -437,7 +437,8 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ saddr->spkt_device[13] = 0; - dev = dev_get_by_name(sock_net(sk), saddr->spkt_device); + rcu_read_lock(); + dev = dev_get_by_name_rcu(sock_net(sk), saddr->spkt_device); err = -ENODEV; if (dev == NULL) goto out_unlock; @@ -500,14 +501,13 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ dev_queue_xmit(skb); - dev_put(dev); + rcu_read_unlock(); return len; out_free: kfree_skb(skb); out_unlock: - if (dev) - dev_put(dev); + rcu_read_unlock(); return err; } @@ -1518,12 +1518,13 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr, return -EOPNOTSUPP; uaddr->sa_family = AF_PACKET; - dev = dev_get_by_index(sock_net(sk), pkt_sk(sk)->ifindex); - if (dev) { + rcu_read_lock(); + dev = dev_get_by_index_rcu(sock_net(sk), pkt_sk(sk)->ifindex); + if (dev) strlcpy(uaddr->sa_data, dev->name, 15); - dev_put(dev); - } else + else memset(uaddr->sa_data, 0, 14); + rcu_read_unlock(); *uaddr_len = sizeof(*uaddr); return 0; @@ -1543,16 +1544,17 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_family = AF_PACKET; sll->sll_ifindex = po->ifindex; sll->sll_protocol = po->num; - dev = dev_get_by_index(sock_net(sk), po->ifindex); + rcu_read_lock(); + dev = dev_get_by_index_rcu(sock_net(sk), po->ifindex); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len); - dev_put(dev); } else { sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ sll->sll_halen = 0; } + rcu_read_unlock(); *uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen; return 0; -- cgit v1.2.3 From f1a28eab20076542322fcab3efa016834bd732f2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 2 Nov 2009 11:21:37 +0100 Subject: ip6tnl: less dev_put() calls Using dev_get_by_index_rcu() in ip6_tnl_rcv_ctl() & ip6_tnl_xmit_ctl() avoids touching device refcount. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 6c1b5c98e81..1d614113a4b 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -658,6 +658,7 @@ static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, IP6_ECN_set_ce(ipv6_hdr(skb)); } +/* called with rcu_read_lock() */ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) { struct ip6_tnl_parm *p = &t->parms; @@ -668,15 +669,13 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) struct net_device *ldev = NULL; if (p->link) - ldev = dev_get_by_index(net, p->link); + ldev = dev_get_by_index_rcu(net, p->link); if ((ipv6_addr_is_multicast(&p->laddr) || likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) ret = 1; - if (ldev) - dev_put(ldev); } return ret; } @@ -804,8 +803,9 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) if (p->flags & IP6_TNL_F_CAP_XMIT) { struct net_device *ldev = NULL; + rcu_read_lock(); if (p->link) - ldev = dev_get_by_index(net, p->link); + ldev = dev_get_by_index_rcu(net, p->link); if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0))) printk(KERN_WARNING @@ -819,8 +819,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) p->name); else ret = 1; - if (ldev) - dev_put(ldev); + rcu_read_unlock(); } return ret; } -- cgit v1.2.3 From 16ba5e8e7c01d2da87ff1d17e83545f164665b5c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 2 Nov 2009 12:10:39 +0100 Subject: ipv6: no more dev_put() in inet6_bind() Avoids touching device refcount in inet6_bind(), thanks to RCU Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index b6d05881867..9105b25defe 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -314,6 +314,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_type != IPV6_ADDR_ANY) { struct net_device *dev = NULL; + rcu_read_lock(); if (addr_type & IPV6_ADDR_LINKLOCAL) { if (addr_len >= sizeof(struct sockaddr_in6) && addr->sin6_scope_id) { @@ -326,12 +327,12 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) /* Binding to link-local address requires an interface */ if (!sk->sk_bound_dev_if) { err = -EINVAL; - goto out; + goto out_unlock; } - dev = dev_get_by_index(net, sk->sk_bound_dev_if); + dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; - goto out; + goto out_unlock; } } @@ -342,14 +343,11 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (!(addr_type & IPV6_ADDR_MULTICAST)) { if (!ipv6_chk_addr(net, &addr->sin6_addr, dev, 0)) { - if (dev) - dev_put(dev); err = -EADDRNOTAVAIL; - goto out; + goto out_unlock; } } - if (dev) - dev_put(dev); + rcu_read_unlock(); } } @@ -381,6 +379,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) out: release_sock(sk); return err; +out_unlock: + rcu_read_unlock(); + goto out; } EXPORT_SYMBOL(inet6_bind); -- cgit v1.2.3 From 536b2e92f1b7a86e177aeced097e4c051eeebe7d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 2 Nov 2009 12:21:06 +0100 Subject: ipv6: no more dev_put() in datagram_send_ctl() Avoids touching device refcount in datagram_send_ctl(), thanks to RCU Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/datagram.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 9f70452a69e..e6f9cdf780f 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -537,12 +537,17 @@ int datagram_send_ctl(struct net *net, addr_type = __ipv6_addr_type(&src_info->ipi6_addr); + rcu_read_lock(); if (fl->oif) { - dev = dev_get_by_index(net, fl->oif); - if (!dev) + dev = dev_get_by_index_rcu(net, fl->oif); + if (!dev) { + rcu_read_unlock(); return -ENODEV; - } else if (addr_type & IPV6_ADDR_LINKLOCAL) + } + } else if (addr_type & IPV6_ADDR_LINKLOCAL) { + rcu_read_unlock(); return -EINVAL; + } if (addr_type != IPV6_ADDR_ANY) { int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; @@ -553,8 +558,7 @@ int datagram_send_ctl(struct net *net, ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr); } - if (dev) - dev_put(dev); + rcu_read_unlock(); if (err) goto exit_f; -- cgit v1.2.3 From 9aa4aee30f4d155fc91abbaecfef9b3bb759699e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 08:43:48 +0100 Subject: mac80211: make CALL_TXH a statement The multi-line code in this macro wasn't wrapped in do {} while (0) so we cannot use it in an if() branch safely in the future -- fix that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 844609c2326..c7dc8ccff5b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1200,23 +1200,25 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) struct sk_buff *skb = tx->skb; ieee80211_tx_result res = TX_DROP; -#define CALL_TXH(txh) \ - res = txh(tx); \ - if (res != TX_CONTINUE) \ - goto txh_done; - - CALL_TXH(ieee80211_tx_h_check_assoc) - CALL_TXH(ieee80211_tx_h_ps_buf) - CALL_TXH(ieee80211_tx_h_select_key) - CALL_TXH(ieee80211_tx_h_michael_mic_add) - CALL_TXH(ieee80211_tx_h_rate_ctrl) - CALL_TXH(ieee80211_tx_h_misc) - CALL_TXH(ieee80211_tx_h_sequence) - CALL_TXH(ieee80211_tx_h_fragment) +#define CALL_TXH(txh) \ + do { \ + res = txh(tx); \ + if (res != TX_CONTINUE) \ + goto txh_done; \ + } while (0) + + CALL_TXH(ieee80211_tx_h_check_assoc); + CALL_TXH(ieee80211_tx_h_ps_buf); + CALL_TXH(ieee80211_tx_h_select_key); + CALL_TXH(ieee80211_tx_h_michael_mic_add); + CALL_TXH(ieee80211_tx_h_rate_ctrl); + CALL_TXH(ieee80211_tx_h_misc); + CALL_TXH(ieee80211_tx_h_sequence); + CALL_TXH(ieee80211_tx_h_fragment); /* handlers after fragment must be aware of tx info fragmentation! */ - CALL_TXH(ieee80211_tx_h_stats) - CALL_TXH(ieee80211_tx_h_encrypt) - CALL_TXH(ieee80211_tx_h_calculate_duration) + CALL_TXH(ieee80211_tx_h_stats); + CALL_TXH(ieee80211_tx_h_encrypt); + CALL_TXH(ieee80211_tx_h_calculate_duration); #undef CALL_TXH txh_done: -- cgit v1.2.3 From 6d3560d4fc9c5b9fe1a07a63926ea70512c69c32 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 31 Oct 2009 07:44:08 +0100 Subject: mac80211: fix scan abort sanity checks Since sometimes mac80211 queues up a scan request to only act on it later, it must be allowed to (internally) cancel a not-yet-running scan, e.g. when the interface is taken down. This condition was missing since we always checked only the local->scanning variable which isn't yet set in that situation. Reported-by: Luis R. Rodriguez Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index c46ac01e2a8..88a9a1be314 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -288,10 +288,14 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) mutex_lock(&local->scan_mtx); - if (WARN_ON(!local->scanning)) { - mutex_unlock(&local->scan_mtx); - return; - } + /* + * It's ok to abort a not-yet-running scan (that + * we have one at all will be verified by checking + * local->scan_req next), but not to complete it + * successfully. + */ + if (WARN_ON(!local->scanning && !aborted)) + aborted = true; if (WARN_ON(!local->scan_req)) { mutex_unlock(&local->scan_mtx); -- cgit v1.2.3 From c5f8289cd9b2e31fca506cb82f4aaa5ffc468602 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 1 Nov 2009 11:18:49 +0200 Subject: cfg80211: Fix WEXT compat siwauth wpa and group cipher Neither of these commands should clear the current configuration value if they return error. Furthermore, cfg80211_set_cipher_group() should be able to handle IW_AUTH_CIPHER_NONE without reporting error. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/wireless/wext-compat.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 561a45cf2a6..41abcbdc5fb 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -904,8 +904,6 @@ static int cfg80211_set_auth_alg(struct wireless_dev *wdev, static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) { - wdev->wext.connect.crypto.wpa_versions = 0; - if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2| IW_AUTH_WPA_VERSION_DISABLED)) @@ -933,8 +931,6 @@ static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions) static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) { - wdev->wext.connect.crypto.cipher_group = 0; - if (cipher & IW_AUTH_CIPHER_WEP40) wdev->wext.connect.crypto.cipher_group = WLAN_CIPHER_SUITE_WEP40; @@ -950,6 +946,8 @@ static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher) else if (cipher & IW_AUTH_CIPHER_AES_CMAC) wdev->wext.connect.crypto.cipher_group = WLAN_CIPHER_SUITE_AES_CMAC; + else if (cipher & IW_AUTH_CIPHER_NONE) + wdev->wext.connect.crypto.cipher_group = 0; else return -EINVAL; -- cgit v1.2.3 From 584991dccfd347cd2e1675ab262998f6c335d3c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Nov 2009 13:32:03 +0100 Subject: cfg80211: validate scan channels Currently it is possible to request a scan on only disabled channels, which could be problematic for some drivers. Reject such scans, and also ignore disabled channels that are given. This resuls in the scan begin/end event only including channels that are actually used. This makes the mac80211 check for disabled channels superfluous. At the same time, remove the no-IBSS check from mac80211 -- nothing says that we should not find any networks on channels that cannot be used for an IBSS, even when operating in IBSS mode. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 13 ++----------- net/wireless/nl80211.c | 34 +++++++++++++++++++++++++++------- net/wireless/scan.c | 6 ++++++ 3 files changed, 35 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 88a9a1be314..4cf387c944b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -614,23 +614,14 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, { int skip; struct ieee80211_channel *chan; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; skip = 0; chan = local->scan_req->channels[local->scan_channel_idx]; - if (chan->flags & IEEE80211_CHAN_DISABLED || - (sdata->vif.type == NL80211_IFTYPE_ADHOC && - chan->flags & IEEE80211_CHAN_NO_IBSS)) + local->scan_channel = chan; + if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) skip = 1; - if (!skip) { - local->scan_channel = chan; - if (ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_CHANNEL)) - skip = 1; - } - /* advance state machine to next channel/band */ local->scan_channel_idx++; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f48394126bf..8ed62b6c172 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2988,7 +2988,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) goto out; } - request->n_channels = n_channels; if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; request->n_ssids = n_ssids; @@ -2999,32 +2998,53 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->ie = (void *)(request->channels + n_channels); } + i = 0; if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { /* user specified, bail out if channel not found */ - request->n_channels = n_channels; - i = 0; nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) { - request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr)); - if (!request->channels[i]) { + struct ieee80211_channel *chan; + + chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); + + if (!chan) { err = -EINVAL; goto out_free; } + + /* ignore disabled channels */ + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; i++; } } else { /* all channels */ - i = 0; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { int j; if (!wiphy->bands[band]) continue; for (j = 0; j < wiphy->bands[band]->n_channels; j++) { - request->channels[i] = &wiphy->bands[band]->channels[j]; + struct ieee80211_channel *chan; + + chan = &wiphy->bands[band]->channels[j]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; i++; } } } + if (!i) { + err = -EINVAL; + goto out_free; + } + + request->n_channels = i; + i = 0; if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2e8c515f3c5..e2d344ff674 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -650,9 +650,15 @@ int cfg80211_wext_siwscan(struct net_device *dev, i = 0; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { int j; + if (!wiphy->bands[band]) continue; + for (j = 0; j < wiphy->bands[band]->n_channels; j++) { + /* ignore disabled channels */ + if (wiphy->bands[band]->channels[j].flags & + IEEE80211_CHAN_DISABLED) + continue; /* If we have a wireless request structure and the * wireless request specifies frequencies, then search -- cgit v1.2.3 From 4b7673a04a16f1d8faf1e367ae28a6ee1671843d Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Mon, 2 Nov 2009 22:41:28 +0000 Subject: Phonet: remove tautologies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These checks don't make sense anymore since rtnl_notify() cannot fail. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/pn_netlink.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c index d8f5d3fb9ee..609e509b369 100644 --- a/net/phonet/pn_netlink.c +++ b/net/phonet/pn_netlink.c @@ -53,8 +53,7 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr) RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL); return; errout: - if (err < 0) - rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err); + rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err); } static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = { @@ -212,8 +211,7 @@ void rtm_phonet_notify(int event, struct net_device *dev, u8 dst) RTNLGRP_PHONET_ROUTE, NULL, GFP_KERNEL); return; errout: - if (err < 0) - rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_ROUTE, err); + rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_ROUTE, err); } static const struct nla_policy rtm_phonet_policy[RTA_MAX+1] = { -- cgit v1.2.3 From d0075634cf9d288988f57392a1f132d2053af961 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 4 Nov 2009 05:23:31 -0800 Subject: em_meta: avoid one dev_put() Another rcu conversion to avoid one dev_hold()/dev_put() pair Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/em_meta.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 18d85d25910..8e8d836f00c 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -303,17 +303,17 @@ META_COLLECTOR(var_sk_bound_if) { SKIP_NONLOCAL(skb); - if (skb->sk->sk_bound_dev_if == 0) { + if (skb->sk->sk_bound_dev_if == 0) { dst->value = (unsigned long) "any"; dst->len = 3; - } else { + } else { struct net_device *dev; - dev = dev_get_by_index(&init_net, skb->sk->sk_bound_dev_if); + rcu_read_lock(); + dev = dev_get_by_index_rcu(&init_net, skb->sk->sk_bound_dev_if); *err = var_dev(dev, dst); - if (dev) - dev_put(dev); - } + rcu_read_unlock(); + } } META_COLLECTOR(int_sk_refcnt) -- cgit v1.2.3 From c6d14c84566d6b70ad9dc1618db0dec87cca9300 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 4 Nov 2009 05:43:23 -0800 Subject: net: Introduce for_each_netdev_rcu() iterator Adds RCU management to the list of netdevices. Convert some for_each_netdev() users to RCU version, if it can avoid read_lock-ing dev_base_lock Ie: read_lock(&dev_base_loack); for_each_netdev(net, dev) some_action(); read_unlock(&dev_base_lock); becomes : rcu_read_lock(); for_each_netdev_rcu(net, dev) some_action(); rcu_read_unlock(); Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 30 ++++++++++++++++-------------- net/decnet/af_decnet.c | 6 +++--- net/decnet/dn_fib.c | 6 +++--- net/decnet/dn_route.c | 6 +++--- net/ipv4/devinet.c | 30 +++++++++++------------------- net/ipv6/addrconf.c | 20 +++++++------------- net/ipv6/anycast.c | 6 +++--- net/netrom/nr_route.c | 15 ++++++++------- net/rose/rose_route.c | 18 +++++++++--------- net/sctp/protocol.c | 6 +++--- 11 files changed, 68 insertions(+), 77 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index bcf1083857f..5077de02831 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1081,6 +1081,8 @@ extern rwlock_t dev_base_lock; /* Device list lock */ #define for_each_netdev(net, d) \ list_for_each_entry(d, &(net)->dev_base_head, dev_list) +#define for_each_netdev_rcu(net, d) \ + list_for_each_entry_rcu(d, &(net)->dev_base_head, dev_list) #define for_each_netdev_safe(net, d, n) \ list_for_each_entry_safe(d, n, &(net)->dev_base_head, dev_list) #define for_each_netdev_continue(net, d) \ diff --git a/net/core/dev.c b/net/core/dev.c index 76a1502efe6..bf629ac08b8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -175,7 +175,7 @@ static struct list_head ptype_all __read_mostly; /* Taps */ * The @dev_base_head list is protected by @dev_base_lock and the rtnl * semaphore. * - * Pure readers hold dev_base_lock for reading. + * Pure readers hold dev_base_lock for reading, or rcu_read_lock() * * Writers must hold the rtnl semaphore while they loop through the * dev_base_head list, and hold dev_base_lock for writing when they do the @@ -212,7 +212,7 @@ static int list_netdevice(struct net_device *dev) ASSERT_RTNL(); write_lock_bh(&dev_base_lock); - list_add_tail(&dev->dev_list, &net->dev_base_head); + list_add_tail_rcu(&dev->dev_list, &net->dev_base_head); hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); hlist_add_head_rcu(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); @@ -229,7 +229,7 @@ static void unlist_netdevice(struct net_device *dev) /* Unlink dev from the device chain */ write_lock_bh(&dev_base_lock); - list_del(&dev->dev_list); + list_del_rcu(&dev->dev_list); hlist_del_rcu(&dev->name_hlist); hlist_del_rcu(&dev->index_hlist); write_unlock_bh(&dev_base_lock); @@ -799,15 +799,15 @@ struct net_device *dev_get_by_flags(struct net *net, unsigned short if_flags, struct net_device *dev, *ret; ret = NULL; - read_lock(&dev_base_lock); - for_each_netdev(net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { if (((dev->flags ^ if_flags) & mask) == 0) { dev_hold(dev); ret = dev; break; } } - read_unlock(&dev_base_lock); + rcu_read_unlock(); return ret; } EXPORT_SYMBOL(dev_get_by_flags); @@ -3077,18 +3077,18 @@ static int dev_ifconf(struct net *net, char __user *arg) * in detail. */ void *dev_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) + __acquires(RCU) { struct net *net = seq_file_net(seq); loff_t off; struct net_device *dev; - read_lock(&dev_base_lock); + rcu_read_lock(); if (!*pos) return SEQ_START_TOKEN; off = 1; - for_each_netdev(net, dev) + for_each_netdev_rcu(net, dev) if (off++ == *pos) return dev; @@ -3097,16 +3097,18 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos) void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct net *net = seq_file_net(seq); + struct net_device *dev = (v == SEQ_START_TOKEN) ? + first_net_device(seq_file_net(seq)) : + next_net_device((struct net_device *)v); + ++*pos; - return v == SEQ_START_TOKEN ? - first_net_device(net) : next_net_device((struct net_device *)v); + return rcu_dereference(dev); } void dev_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) + __releases(RCU) { - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 664965c87e1..2e355841ca9 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -749,9 +749,9 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (!(saddr->sdn_flags & SDF_WILD)) { if (le16_to_cpu(saddr->sdn_nodeaddrl)) { - read_lock(&dev_base_lock); + rcu_read_lock(); ldev = NULL; - for_each_netdev(&init_net, dev) { + for_each_netdev_rcu(&init_net, dev) { if (!dev->dn_ptr) continue; if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) { @@ -759,7 +759,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) break; } } - read_unlock(&dev_base_lock); + rcu_read_unlock(); if (ldev == NULL) return -EADDRNOTAVAIL; } diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 27ea2e9b080..fd641f65e09 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -607,8 +607,8 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) ASSERT_RTNL(); /* Scan device list */ - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { dn_db = dev->dn_ptr; if (dn_db == NULL) continue; @@ -619,7 +619,7 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) } } } - read_unlock(&dev_base_lock); + rcu_read_unlock(); if (found_it == 0) { fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa); diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 57662cabaf9..860286a3921 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -908,8 +908,8 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old dev_put(dev_out); goto out; } - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { if (!dev->dn_ptr) continue; if (!dn_dev_islocal(dev, oldflp->fld_src)) @@ -922,7 +922,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old dev_out = dev; break; } - read_unlock(&dev_base_lock); + rcu_read_unlock(); if (dev_out == NULL) goto out; dev_hold(dev_out); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ccccaae50b2..8aa7a134c1f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -876,19 +876,16 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) if (!addr) addr = ifa->ifa_local; } endfor_ifa(in_dev); -no_in_dev: - rcu_read_unlock(); +no_in_dev: if (addr) - goto out; + goto out_unlock; /* Not loopback addresses on loopback should be preferred in this case. It is importnat that lo is the first interface in dev_base list. */ - read_lock(&dev_base_lock); - rcu_read_lock(); - for_each_netdev(net, dev) { + for_each_netdev_rcu(net, dev) { if ((in_dev = __in_dev_get_rcu(dev)) == NULL) continue; @@ -896,12 +893,11 @@ no_in_dev: if (ifa->ifa_scope != RT_SCOPE_LINK && ifa->ifa_scope <= scope) { addr = ifa->ifa_local; - goto out_unlock_both; + goto out_unlock; } } endfor_ifa(in_dev); } -out_unlock_both: - read_unlock(&dev_base_lock); +out_unlock: rcu_read_unlock(); out: return addr; @@ -962,9 +958,8 @@ __be32 inet_confirm_addr(struct in_device *in_dev, return confirm_addr_indev(in_dev, dst, local, scope); net = dev_net(in_dev->dev); - read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(net, dev) { + for_each_netdev_rcu(net, dev) { if ((in_dev = __in_dev_get_rcu(dev))) { addr = confirm_addr_indev(in_dev, dst, local, scope); if (addr) @@ -972,7 +967,6 @@ __be32 inet_confirm_addr(struct in_device *in_dev, } } rcu_read_unlock(); - read_unlock(&dev_base_lock); return addr; } @@ -1240,18 +1234,18 @@ static void devinet_copy_dflt_conf(struct net *net, int i) { struct net_device *dev; - read_lock(&dev_base_lock); - for_each_netdev(net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { struct in_device *in_dev; - rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); if (in_dev && !test_bit(i, in_dev->cnf.state)) in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i]; - rcu_read_unlock(); } - read_unlock(&dev_base_lock); + rcu_read_unlock(); } +/* called with RTNL locked */ static void inet_forward_change(struct net *net) { struct net_device *dev; @@ -1260,7 +1254,6 @@ static void inet_forward_change(struct net *net) IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on; IPV4_DEVCONF_DFLT(net, FORWARDING) = on; - read_lock(&dev_base_lock); for_each_netdev(net, dev) { struct in_device *in_dev; if (on) @@ -1271,7 +1264,6 @@ static void inet_forward_change(struct net *net) IN_DEV_CONF_SET(in_dev, FORWARDING, on); rcu_read_unlock(); } - read_unlock(&dev_base_lock); } static int devinet_conf_proc(ctl_table *ctl, int write, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 91864840961..024bba30de2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -481,9 +481,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf) struct net_device *dev; struct inet6_dev *idev; - read_lock(&dev_base_lock); - for_each_netdev(net, dev) { - rcu_read_lock(); + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { idev = __in6_dev_get(dev); if (idev) { int changed = (!idev->cnf.forwarding) ^ (!newf); @@ -491,9 +490,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf) if (changed) dev_forward_change(idev); } - rcu_read_unlock(); } - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) @@ -1137,10 +1135,9 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, hiscore->rule = -1; hiscore->ifa = NULL; - read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(net, dev) { + for_each_netdev_rcu(net, dev) { struct inet6_dev *idev; /* Candidate Source Address (section 4) @@ -1235,7 +1232,6 @@ try_nextdev: read_unlock_bh(&idev->lock); } rcu_read_unlock(); - read_unlock(&dev_base_lock); if (!hiscore->ifa) return -EADDRNOTAVAIL; @@ -4052,9 +4048,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf) struct net_device *dev; struct inet6_dev *idev; - read_lock(&dev_base_lock); - for_each_netdev(net, dev) { - rcu_read_lock(); + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { idev = __in6_dev_get(dev); if (idev) { int changed = (!idev->cnf.disable_ipv6) ^ (!newf); @@ -4062,9 +4057,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf) if (changed) dev_disable_change(idev); } - rcu_read_unlock(); } - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 1ae58bec1de..2f00ca83f04 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -404,13 +404,13 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, if (dev) return ipv6_chk_acast_dev(dev, addr); - read_lock(&dev_base_lock); - for_each_netdev(net, dev) + rcu_read_lock(); + for_each_netdev_rcu(net, dev) if (ipv6_chk_acast_dev(dev, addr)) { found = 1; break; } - read_unlock(&dev_base_lock); + rcu_read_unlock(); return found; } diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index 4eb1ac9a767..aacba76070f 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -597,15 +597,15 @@ struct net_device *nr_dev_first(void) { struct net_device *dev, *first = NULL; - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM) if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; } if (first) dev_hold(first); - read_unlock(&dev_base_lock); + rcu_read_unlock(); return first; } @@ -617,16 +617,17 @@ struct net_device *nr_dev_get(ax25_address *addr) { struct net_device *dev; - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { + if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && + ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) { dev_hold(dev); goto out; } } dev = NULL; out: - read_unlock(&dev_base_lock); + rcu_read_unlock(); return dev; } diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 9478d9b3d97..d936226916f 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -600,13 +600,13 @@ struct net_device *rose_dev_first(void) { struct net_device *dev, *first = NULL; - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE) if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; } - read_unlock(&dev_base_lock); + rcu_read_unlock(); return first; } @@ -618,8 +618,8 @@ struct net_device *rose_dev_get(rose_address *addr) { struct net_device *dev; - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) { dev_hold(dev); goto out; @@ -627,7 +627,7 @@ struct net_device *rose_dev_get(rose_address *addr) } dev = NULL; out: - read_unlock(&dev_base_lock); + rcu_read_unlock(); return dev; } @@ -635,14 +635,14 @@ static int rose_dev_exists(rose_address *addr) { struct net_device *dev; - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) goto out; } dev = NULL; out: - read_unlock(&dev_base_lock); + rcu_read_unlock(); return dev != NULL; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d9f4cc2c786..fe44c57101d 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -205,14 +205,14 @@ static void sctp_get_local_addr_list(void) struct list_head *pos; struct sctp_af *af; - read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { __list_for_each(pos, &sctp_address_families) { af = list_entry(pos, struct sctp_af, list); af->copy_addrlist(&sctp_local_addr_list, dev); } } - read_unlock(&dev_base_lock); + rcu_read_unlock(); } /* Free the existing local addresses. */ -- cgit v1.2.3 From b4d745db12bd2d45a456565ed63325bbfc689e68 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 4 Nov 2009 10:59:38 -0800 Subject: decnet: avoid touching device refcount in dn_dev_by_index() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/decnet/dn_dev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 6e1f085db06..d82694d930b 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -600,15 +600,17 @@ static void dn_dev_check_default(struct net_device *dev) dev_put(dev); } +/* + * Called with RTNL + */ static struct dn_dev *dn_dev_by_index(int ifindex) { struct net_device *dev; struct dn_dev *dn_dev = NULL; - dev = dev_get_by_index(&init_net, ifindex); - if (dev) { + + dev = __dev_get_by_index(&init_net, ifindex); + if (dev) dn_dev = dev->dn_ptr; - dev_put(dev); - } return dn_dev; } -- cgit v1.2.3 From 9481721be10a1bfd1ee9ccf507eecd7f37caa5ec Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 4 Nov 2009 21:14:31 +0100 Subject: netfilter: remove synchronize_net() calls in ip_queue/ip6_queue nf_unregister_queue_handlers() already does a synchronize_rcu() call, we dont need to do it again in callers. Signed-off-by: Eric Dumazet Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv6/netfilter/ip6_queue.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index c156db21598..9811a456fb5 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -622,7 +622,7 @@ cleanup_netlink_notifier: static void __exit ip_queue_fini(void) { nf_unregister_queue_handlers(&nfqh); - synchronize_net(); + ipq_flush(NULL, 0); #ifdef CONFIG_SYSCTL diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 1cf3f0c6a95..a82016fd5d6 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -625,7 +625,7 @@ cleanup_netlink_notifier: static void __exit ip6_queue_fini(void) { nf_unregister_queue_handlers(&nfqh); - synchronize_net(); + ipq_flush(NULL, 0); #ifdef CONFIG_SYSCTL -- cgit v1.2.3 From 7fdad987d63f02c8fba30276ba395ac8dc93b719 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 31 Oct 2009 16:15:39 +0100 Subject: cfg80211: remove dead variable commit 211a4d12abf86fe0df4cd68fc6327cbb58f56f81 Author: Johannes Berg Date: Tue Oct 20 15:08:53 2009 +0900 cfg80211: sme: deauthenticate on assoc failure accidentally introduced a dead variable, I had changed the code to not need it while creating the patch and it looks like I forgot to remove the variable (and nobody else noticed either). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/mlme.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 83c2a288dc6..2610b746eff 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -62,7 +62,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) u8 *ie = mgmt->u.assoc_resp.variable; int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); struct cfg80211_internal_bss *bss = NULL; - bool need_connect_result = true; wdev_lock(wdev); @@ -97,7 +96,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) WARN_ON(!bss); } else if (wdev->conn) { cfg80211_sme_failed_assoc(wdev); - need_connect_result = false; /* * do not call connect_result() now because the * sme will schedule work that does it later. -- cgit v1.2.3 From 5ed176e1c425f9bd1af161d66d348f6116a04fc6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Nov 2009 14:42:28 +0100 Subject: mac80211: make ieee80211_find_sta per virtual interface Since we have a TODO item to make all station management dependent on virtual interfaces, I figured I'd start with pushing such a change to drivers before more drivers start using the ieee80211_find_sta() API with a hw pointer and cause us grief later on. For now continue exporting the old API in form of ieee80211_find_sta_by_hw(), but discourage its use strongly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 3 ++- drivers/net/wireless/ath/ath9k/xmit.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- include/net/mac80211.h | 25 +++++++++++++++++++++++-- net/mac80211/sta_info.c | 18 ++++++++++++++++-- 7 files changed, 47 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c880a55939b..355dd1834e1 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -202,7 +202,8 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } rcu_read_lock(); - sta = ieee80211_find_sta(sc->hw, hdr->addr2); + /* XXX: use ieee80211_find_sta! */ + sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr2); if (sta) { an = (struct ath_node *) sta->drv_priv; if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2a4efcbced6..8e052f406c3 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -282,7 +282,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_lock(); - sta = ieee80211_find_sta(sc->hw, hdr->addr1); + /* XXX: use ieee80211_find_sta! */ + sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr1); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 819a81bbb1b..dc81e19674f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -913,7 +913,8 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); - sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); + sta = ieee80211_find_sta(priv->vif, + priv->stations[sta_id].sta.sta.addr); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7373b2f50ac..e0b5b4aef41 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2300,7 +2300,7 @@ static void iwl_ht_conf(struct iwl_priv *priv, switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, priv->bssid); + sta = ieee80211_find_sta(priv->vif, priv->bssid); if (sta) { struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; int maxstreams; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 74cc8dbe935..eba36f73738 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1017,7 +1017,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) */ if (priv->current_ht_config.is_ht) { rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, addr); + sta = ieee80211_find_sta(priv->vif, addr); if (sta) { memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); cur_ht_config = &ht_config; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e12293e60ac..7f035d779db 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2106,15 +2106,36 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, /** * ieee80211_find_sta - find a station * - * @hw: pointer as obtained from ieee80211_alloc_hw() + * @vif: virtual interface to look for station on * @addr: station's address * * This function must be called under RCU lock and the * resulting pointer is only valid under RCU lock as well. */ -struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *addr); +/** + * ieee80211_find_sta_by_hw - find a station on hardware + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @addr: station's address + * + * This function must be called under RCU lock and the + * resulting pointer is only valid under RCU lock as well. + * + * NOTE: This function should not be used! When mac80211 is converted + * internally to properly keep track of stations on multiple + * virtual interfaces, it will not always know which station to + * return here since a single address might be used by multiple + * logical stations (e.g. consider a station connecting to another + * BSSID on the same AP hardware without disconnecting first). + * + * DO NOT USE THIS FUNCTION. + */ +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr); + /** * ieee80211_beacon_loss - inform hardware does not receive beacons * diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 594f2318c3d..cde2da7a74d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -801,8 +801,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, - const u8 *addr) +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr) { struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); @@ -810,4 +810,18 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, return NULL; return &sta->sta; } +EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); + +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, + const u8 *addr) +{ + struct ieee80211_sub_if_data *sdata; + + if (!vif) + return NULL; + + sdata = vif_to_sdata(vif); + + return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); +} EXPORT_SYMBOL(ieee80211_find_sta); -- cgit v1.2.3 From 450aae3d7b60a970f266349a837dfb30a539198b Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 2 Nov 2009 12:33:23 +0530 Subject: mac80211: Fix IBSS merge Currently, in IBSS mode, a single creator would go into a loop trying to merge/scan. This happens because the IBSS timer is rearmed on finishing a scan and the subsequent timer invocation requests another scan immediately. This patch fixes this issue by checking if we have just completed a scan run trying to merge with other IBSS networks. Signed-off-by: Sujith Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ca8ecce31d3..6ae288387a1 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -453,6 +453,10 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); + if (time_before(jiffies, ifibss->last_scan_completed + + IEEE80211_IBSS_MERGE_INTERVAL)) + return; + if (ieee80211_sta_active_ibss(sdata)) return; -- cgit v1.2.3 From c327d96759ac134384114830e19ded80e29fdcc4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Nov 2009 11:31:51 +0100 Subject: mac80211: fix internal scan request The internal scan request mac80211 uses to scan for IBSS networks was set up to contain no channels at all because n_channels wasn't set after setting up the channels array. Fix this to properly scan for networks. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4e80213d6c7..9e6703ff7fb 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -901,6 +901,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) i++; } } + local->int_scan_req->n_channels = i; local->network_latency_notifier.notifier_call = ieee80211_max_network_latency; -- cgit v1.2.3 From 9f9354b92defa15aa0e215946c6e2dbccecb6aa7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 4 Nov 2009 22:05:10 -0800 Subject: net: net/ipv4/devinet.c cleanups As pointed by Stephen Rothwell, commit c6d14c84 added a warning : net/ipv4/devinet.c: In function 'inet_select_addr': net/ipv4/devinet.c:902: warning: label 'out' defined but not used delete unused 'out' label and do some cleanups as well Reported-by: Stephen Rothwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 61 +++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 8aa7a134c1f..c2045f9615d 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -140,11 +140,11 @@ void in_dev_finish_destroy(struct in_device *idev) #endif dev_put(dev); if (!idev->dead) - printk("Freeing alive in_device %p\n", idev); - else { + pr_err("Freeing alive in_device %p\n", idev); + else kfree(idev); - } } +EXPORT_SYMBOL(in_dev_finish_destroy); static struct in_device *inetdev_init(struct net_device *dev) { @@ -159,7 +159,8 @@ static struct in_device *inetdev_init(struct net_device *dev) sizeof(in_dev->cnf)); in_dev->cnf.sysctl = NULL; in_dev->dev = dev; - if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) + in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl); + if (!in_dev->arp_parms) goto out_kfree; if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) dev_disable_lro(dev); @@ -413,6 +414,7 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex) rcu_read_unlock(); return in_dev; } +EXPORT_SYMBOL(inetdev_by_index); /* Called only from RTNL semaphored context. No locks. */ @@ -558,7 +560,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg * Determine a default network mask, based on the IP address. */ -static __inline__ int inet_abc_len(__be32 addr) +static inline int inet_abc_len(__be32 addr) { int rc = -1; /* Something else, probably a multicast. */ @@ -647,13 +649,15 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) rtnl_lock(); ret = -ENODEV; - if ((dev = __dev_get_by_name(net, ifr.ifr_name)) == NULL) + dev = __dev_get_by_name(net, ifr.ifr_name); + if (!dev) goto done; if (colon) *colon = ':'; - if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) { + in_dev = __in_dev_get_rtnl(dev); + if (in_dev) { if (tryaddrmatch) { /* Matthias Andree */ /* compare label and address (4.4BSD style) */ @@ -721,7 +725,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) if (!ifa) { ret = -ENOBUFS; - if ((ifa = inet_alloc_ifa()) == NULL) + ifa = inet_alloc_ifa(); + if (!ifa) break; if (colon) memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ); @@ -823,10 +828,10 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len) struct ifreq ifr; int done = 0; - if (!in_dev || (ifa = in_dev->ifa_list) == NULL) + if (!in_dev) goto out; - for (; ifa; ifa = ifa->ifa_next) { + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { if (!buf) { done += sizeof(ifr); continue; @@ -877,16 +882,17 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) addr = ifa->ifa_local; } endfor_ifa(in_dev); -no_in_dev: if (addr) goto out_unlock; +no_in_dev: /* Not loopback addresses on loopback should be preferred in this case. It is importnat that lo is the first interface in dev_base list. */ for_each_netdev_rcu(net, dev) { - if ((in_dev = __in_dev_get_rcu(dev)) == NULL) + in_dev = __in_dev_get_rcu(dev); + if (!in_dev) continue; for_primary_ifa(in_dev) { @@ -899,9 +905,9 @@ no_in_dev: } out_unlock: rcu_read_unlock(); -out: return addr; } +EXPORT_SYMBOL(inet_select_addr); static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, __be32 local, int scope) @@ -937,7 +943,7 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, } } endfor_ifa(in_dev); - return same? addr : 0; + return same ? addr : 0; } /* @@ -960,7 +966,8 @@ __be32 inet_confirm_addr(struct in_device *in_dev, net = dev_net(in_dev->dev); rcu_read_lock(); for_each_netdev_rcu(net, dev) { - if ((in_dev = __in_dev_get_rcu(dev))) { + in_dev = __in_dev_get_rcu(dev); + if (in_dev) { addr = confirm_addr_indev(in_dev, dst, local, scope); if (addr) break; @@ -979,14 +986,16 @@ int register_inetaddr_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&inetaddr_chain, nb); } +EXPORT_SYMBOL(register_inetaddr_notifier); int unregister_inetaddr_notifier(struct notifier_block *nb) { return blocking_notifier_chain_unregister(&inetaddr_chain, nb); } +EXPORT_SYMBOL(unregister_inetaddr_notifier); -/* Rename ifa_labels for a device name change. Make some effort to preserve existing - * alias numbering and to create unique labels if possible. +/* Rename ifa_labels for a device name change. Make some effort to preserve + * existing alias numbering and to create unique labels if possible. */ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) { @@ -1005,11 +1014,10 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) sprintf(old, ":%d", named); dot = old; } - if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) { + if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) strcat(ifa->ifa_label, dot); - } else { + else strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot); - } skip: rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0); } @@ -1056,8 +1064,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, if (!inetdev_valid_mtu(dev->mtu)) break; if (dev->flags & IFF_LOOPBACK) { - struct in_ifaddr *ifa; - if ((ifa = inet_alloc_ifa()) != NULL) { + struct in_ifaddr *ifa = inet_alloc_ifa(); + + if (ifa) { ifa->ifa_local = ifa->ifa_address = htonl(INADDR_LOOPBACK); ifa->ifa_prefixlen = 8; @@ -1178,7 +1187,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) goto cont; if (idx > s_idx) s_ip_idx = 0; - if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) + in_dev = __in_dev_get_rtnl(dev); + if (!in_dev) goto cont; for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; @@ -1673,8 +1683,3 @@ void __init devinet_init(void) rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); } -EXPORT_SYMBOL(in_dev_finish_destroy); -EXPORT_SYMBOL(inet_select_addr); -EXPORT_SYMBOL(inetdev_by_index); -EXPORT_SYMBOL(register_inetaddr_notifier); -EXPORT_SYMBOL(unregister_inetaddr_notifier); -- cgit v1.2.3 From 05eaade2782fb0c90d3034fd7a7d5a16266182bb Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 4 Nov 2009 23:21:44 -0800 Subject: tcp: Do not call IPv4 specific func in tcp_check_req Calling IPv4 specific inet_csk_route_req in tcp_check_req is a bad idea and crashes machine on IPv6 connections, as reported by Valdis Kletnieks Also, all we are really interested in is the timestamp option in the header, so calling tcp_parse_options() with the "estab" set to false flag is an overkill as it tries to parse half a dozen other TCP options. We know whether timestamp should be enabled or not using data from request_sock. Signed-off-by: Gilad Ben-Yossef Tested-by: Valdis.Kletnieks@vt.edu Signed-off-by: David S. Miller --- net/ipv4/tcp_minisocks.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 463d51b53d3..a9d34e224cb 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -500,11 +500,10 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, int paws_reject = 0; struct tcp_options_received tmp_opt; struct sock *child; - struct dst_entry *dst = inet_csk_route_req(sk, req); - tmp_opt.saw_tstamp = 0; - if (th->doff > (sizeof(struct tcphdr)>>2)) { - tcp_parse_options(skb, &tmp_opt, 0, dst); + if ((th->doff > (sizeof(struct tcphdr)>>2)) && (req->ts_recent)) { + tmp_opt.tstamp_ok = 1; + tcp_parse_options(skb, &tmp_opt, 1, NULL); if (tmp_opt.saw_tstamp) { tmp_opt.ts_recent = req->ts_recent; @@ -517,8 +516,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, } } - dst_release(dst); - /* Check for pure retransmitted SYN. */ if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn && flg == TCP_FLAG_SYN && -- cgit v1.2.3 From 6a2a2d6bf8581216e08be15fcb563cfd6c430e1e Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Wed, 4 Nov 2009 23:23:10 -0800 Subject: tcp: Use defaults when no route options are available Trying to parse the option of a SYN packet that we have no route entry for should just use global wide defaults for route entry options. Signed-off-by: Gilad Ben-Yossef Tested-by: Valdis.Kletnieks@vt.edu Signed-off-by: David S. Miller --- include/net/dst.h | 2 +- net/ipv4/tcp_input.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/dst.h b/include/net/dst.h index 39c4a5963e1..387cb3cfde7 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -113,7 +113,7 @@ dst_metric(const struct dst_entry *dst, int metric) static inline u32 dst_feature(const struct dst_entry *dst, u32 feature) { - return dst_metric(dst, RTAX_FEATURES) & feature; + return (dst ? dst_metric(dst, RTAX_FEATURES) & feature : 0); } static inline u32 dst_mtu(const struct dst_entry *dst) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ba0eab65fe8..be0c5bf7bfc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3704,8 +3704,6 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, struct tcphdr *th = tcp_hdr(skb); int length = (th->doff * 4) - sizeof(struct tcphdr); - BUG_ON(!estab && !dst); - ptr = (unsigned char *)(th + 1); opt_rx->saw_tstamp = 0; -- cgit v1.2.3 From 5ae27aa2b16478a84d833ab4065798e752941c5a Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Thu, 5 Nov 2009 14:51:31 +0100 Subject: netfilter: nf_conntrack: avoid additional compare. Signed-off-by: Changli Gao Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_core.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7c9ec3dee96..8e572d7c08c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -511,11 +511,17 @@ static noinline int early_drop(struct net *net, unsigned int hash) cnt++; } - if (ct && unlikely(nf_ct_is_dying(ct) || - !atomic_inc_not_zero(&ct->ct_general.use))) - ct = NULL; - if (ct || cnt >= NF_CT_EVICTION_RANGE) + if (ct != NULL) { + if (likely(!nf_ct_is_dying(ct) && + atomic_inc_not_zero(&ct->ct_general.use))) + break; + else + ct = NULL; + } + + if (cnt >= NF_CT_EVICTION_RANGE) break; + hash = (hash + 1) % nf_conntrack_htable_size; } rcu_read_unlock(); -- cgit v1.2.3 From 76ac894080019c6619d3c3bf615db42a43a77f32 Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Thu, 5 Nov 2009 15:51:19 +0100 Subject: netfilter: nf_nat_helper: tidy up adjust_tcp_sequence The variable 'other_way' gets initialized but is not read afterwards, so remove it. Pass the right arguments to a pr_debug call. While being at tidy up a bit and it fix this checkpatch warning: WARNING: suspect code indent for conditional statements Signed-off-by: Hannes Eder Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_helper.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 09172a65d9b..5bf6a92cc55 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -41,18 +41,14 @@ adjust_tcp_sequence(u32 seq, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { - int dir; - struct nf_nat_seq *this_way, *other_way; + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_seq *this_way = &nat->seq[dir]; - pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n", seq, seq); - - dir = CTINFO2DIR(ctinfo); - - this_way = &nat->seq[dir]; - other_way = &nat->seq[!dir]; + pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n", + seq, sizediff); - pr_debug("nf_nat_resize_packet: Seq_offset before: "); + pr_debug("adjust_tcp_sequence: Seq_offset before: "); DUMP_OFFSET(this_way); spin_lock_bh(&nf_nat_seqofs_lock); @@ -63,13 +59,13 @@ adjust_tcp_sequence(u32 seq, * retransmit */ if (this_way->offset_before == this_way->offset_after || before(this_way->correction_pos, seq)) { - this_way->correction_pos = seq; - this_way->offset_before = this_way->offset_after; - this_way->offset_after += sizediff; + this_way->correction_pos = seq; + this_way->offset_before = this_way->offset_after; + this_way->offset_after += sizediff; } spin_unlock_bh(&nf_nat_seqofs_lock); - pr_debug("nf_nat_resize_packet: Seq_offset after: "); + pr_debug("adjust_tcp_sequence: Seq_offset after: "); DUMP_OFFSET(this_way); } -- cgit v1.2.3 From 13f18aa05f5abe135f47b6417537ae2b2fedc18c Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 5 Nov 2009 20:44:37 -0800 Subject: net: drop capability from protocol definitions struct can_proto had a capability field which wasn't ever used. It is dropped entirely. struct inet_protosw had a capability field which can be more clearly expressed in the code by just checking if sock->type = SOCK_RAW. Signed-off-by: Eric Paris Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/linux/can/core.h | 2 -- include/net/protocol.h | 4 ---- net/can/af_can.c | 5 ----- net/can/bcm.c | 1 - net/can/raw.c | 1 - net/dccp/ipv4.c | 1 - net/dccp/ipv6.c | 1 - net/ipv4/af_inet.c | 5 +---- net/ipv4/udplite.c | 1 - net/ipv6/af_inet6.c | 2 +- net/ipv6/raw.c | 1 - net/ipv6/tcp_ipv6.c | 1 - net/ipv6/udp.c | 1 - net/ipv6/udplite.c | 1 - net/sctp/ipv6.c | 2 -- net/sctp/protocol.c | 2 -- 16 files changed, 2 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/include/linux/can/core.h b/include/linux/can/core.h index 25085cbadcf..6c507bea275 100644 --- a/include/linux/can/core.h +++ b/include/linux/can/core.h @@ -32,14 +32,12 @@ * struct can_proto - CAN protocol structure * @type: type argument in socket() syscall, e.g. SOCK_DGRAM. * @protocol: protocol number in socket() syscall. - * @capability: capability needed to open the socket, or -1 for no restriction. * @ops: pointer to struct proto_ops for sock->ops. * @prot: pointer to struct proto structure. */ struct can_proto { int type; int protocol; - int capability; struct proto_ops *ops; struct proto *prot; }; diff --git a/include/net/protocol.h b/include/net/protocol.h index 89932d45da5..f1effdd3c26 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -82,10 +82,6 @@ struct inet_protosw { struct proto *prot; const struct proto_ops *ops; - int capability; /* Which (if any) capability do - * we need to use this socket - * interface? - */ char no_check; /* checksum on rcv/xmit/none? */ unsigned char flags; /* See INET_PROTOSW_* below. */ }; diff --git a/net/can/af_can.c b/net/can/af_can.c index 3f2eb27e1ff..9c0426dc318 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -160,11 +160,6 @@ static int can_create(struct net *net, struct socket *sock, int protocol) goto errout; } - if (cp->capability >= 0 && !capable(cp->capability)) { - err = -EPERM; - goto errout; - } - sock->ops = cp->ops; sk = sk_alloc(net, PF_CAN, GFP_KERNEL, cp->prot); diff --git a/net/can/bcm.c b/net/can/bcm.c index 2f47039c79d..67b5433db13 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1576,7 +1576,6 @@ static struct proto bcm_proto __read_mostly = { static struct can_proto bcm_can_proto __read_mostly = { .type = SOCK_DGRAM, .protocol = CAN_BCM, - .capability = -1, .ops = &bcm_ops, .prot = &bcm_proto, }; diff --git a/net/can/raw.c b/net/can/raw.c index 6e77db58b9e..abca920440b 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -742,7 +742,6 @@ static struct proto raw_proto __read_mostly = { static struct can_proto raw_can_proto __read_mostly = { .type = SOCK_RAW, .protocol = CAN_RAW, - .capability = -1, .ops = &raw_ops, .prot = &raw_proto, }; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 00028d4b09d..2423a086673 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -991,7 +991,6 @@ static struct inet_protosw dccp_v4_protosw = { .protocol = IPPROTO_DCCP, .prot = &dccp_v4_prot, .ops = &inet_dccp_ops, - .capability = -1, .no_check = 0, .flags = INET_PROTOSW_ICSK, }; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 6d89f9f7d5d..50ea91a7770 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1185,7 +1185,6 @@ static struct inet_protosw dccp_v6_protosw = { .protocol = IPPROTO_DCCP, .prot = &dccp_v6_prot, .ops = &inet6_dccp_ops, - .capability = -1, .flags = INET_PROTOSW_ICSK, }; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 538e84d0bcb..180ec4c9491 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -325,7 +325,7 @@ lookup_protocol: } err = -EPERM; - if (answer->capability > 0 && !capable(answer->capability)) + if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) goto out_rcu_unlock; err = -EAFNOSUPPORT; @@ -947,7 +947,6 @@ static struct inet_protosw inetsw_array[] = .protocol = IPPROTO_TCP, .prot = &tcp_prot, .ops = &inet_stream_ops, - .capability = -1, .no_check = 0, .flags = INET_PROTOSW_PERMANENT | INET_PROTOSW_ICSK, @@ -958,7 +957,6 @@ static struct inet_protosw inetsw_array[] = .protocol = IPPROTO_UDP, .prot = &udp_prot, .ops = &inet_dgram_ops, - .capability = -1, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_PERMANENT, }, @@ -969,7 +967,6 @@ static struct inet_protosw inetsw_array[] = .protocol = IPPROTO_IP, /* wild card */ .prot = &raw_prot, .ops = &inet_sockraw_ops, - .capability = CAP_NET_RAW, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_REUSE, } diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 470c504b955..66f79513f4a 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -64,7 +64,6 @@ static struct inet_protosw udplite4_protosw = { .protocol = IPPROTO_UDPLITE, .prot = &udplite_prot, .ops = &inet_dgram_ops, - .capability = -1, .no_check = 0, /* must checksum (RFC 3828) */ .flags = INET_PROTOSW_PERMANENT, }; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 9105b25defe..1b388935659 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -158,7 +158,7 @@ lookup_protocol: } err = -EPERM; - if (answer->capability > 0 && !capable(answer->capability)) + if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) goto out_rcu_unlock; sock->ops = answer->ops; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index cb834ab7f07..818ef21ba76 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1336,7 +1336,6 @@ static struct inet_protosw rawv6_protosw = { .protocol = IPPROTO_IP, /* wild card */ .prot = &rawv6_prot, .ops = &inet6_sockraw_ops, - .capability = CAP_NET_RAW, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_REUSE, }; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 34925f089e0..696a22f034e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2112,7 +2112,6 @@ static struct inet_protosw tcpv6_protosw = { .protocol = IPPROTO_TCP, .prot = &tcpv6_prot, .ops = &inet6_stream_ops, - .capability = -1, .no_check = 0, .flags = INET_PROTOSW_PERMANENT | INET_PROTOSW_ICSK, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index d3b59d73f50..bbe2f3e445f 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1286,7 +1286,6 @@ static struct inet_protosw udpv6_protosw = { .protocol = IPPROTO_UDP, .prot = &udpv6_prot, .ops = &inet6_dgram_ops, - .capability =-1, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_PERMANENT, }; diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index d737a27ee01..6ea6938919e 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -62,7 +62,6 @@ static struct inet_protosw udplite6_protosw = { .protocol = IPPROTO_UDPLITE, .prot = &udplitev6_prot, .ops = &inet6_dgram_ops, - .capability = -1, .no_check = 0, .flags = INET_PROTOSW_PERMANENT, }; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index bb280e60e00..bacd6a7318b 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -930,7 +930,6 @@ static struct inet_protosw sctpv6_seqpacket_protosw = { .protocol = IPPROTO_SCTP, .prot = &sctpv6_prot, .ops = &inet6_seqpacket_ops, - .capability = -1, .no_check = 0, .flags = SCTP_PROTOSW_FLAG }; @@ -939,7 +938,6 @@ static struct inet_protosw sctpv6_stream_protosw = { .protocol = IPPROTO_SCTP, .prot = &sctpv6_prot, .ops = &inet6_seqpacket_ops, - .capability = -1, .no_check = 0, .flags = SCTP_PROTOSW_FLAG, }; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index fe44c57101d..08ef203d36a 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -909,7 +909,6 @@ static struct inet_protosw sctp_seqpacket_protosw = { .protocol = IPPROTO_SCTP, .prot = &sctp_prot, .ops = &inet_seqpacket_ops, - .capability = -1, .no_check = 0, .flags = SCTP_PROTOSW_FLAG }; @@ -918,7 +917,6 @@ static struct inet_protosw sctp_stream_protosw = { .protocol = IPPROTO_SCTP, .prot = &sctp_prot, .ops = &inet_seqpacket_ops, - .capability = -1, .no_check = 0, .flags = SCTP_PROTOSW_FLAG }; -- cgit v1.2.3 From 3f378b684453f2a028eda463ce383370545d9cc9 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 5 Nov 2009 22:18:14 -0800 Subject: net: pass kern to net_proto_family create function The generic __sock_create function has a kern argument which allows the security system to make decisions based on if a socket is being created by the kernel or by userspace. This patch passes that flag to the net_proto_family specific create function, so it can do the same thing. Signed-off-by: Eric Paris Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- drivers/isdn/mISDN/socket.c | 2 +- drivers/net/pppox.c | 3 ++- include/linux/net.h | 3 ++- net/appletalk/ddp.c | 3 ++- net/atm/pvc.c | 3 ++- net/atm/svc.c | 7 ++++--- net/ax25/af_ax25.c | 3 ++- net/bluetooth/af_bluetooth.c | 5 +++-- net/bluetooth/bnep/sock.c | 3 ++- net/bluetooth/cmtp/sock.c | 3 ++- net/bluetooth/hci_sock.c | 3 ++- net/bluetooth/hidp/sock.c | 3 ++- net/bluetooth/l2cap.c | 3 ++- net/bluetooth/rfcomm/sock.c | 3 ++- net/bluetooth/sco.c | 3 ++- net/can/af_can.c | 3 ++- net/decnet/af_decnet.c | 3 ++- net/econet/af_econet.c | 3 ++- net/ieee802154/af_ieee802154.c | 2 +- net/ipv4/af_inet.c | 3 ++- net/ipv6/af_inet6.c | 3 ++- net/ipx/af_ipx.c | 3 ++- net/irda/af_irda.c | 7 ++++--- net/iucv/af_iucv.c | 3 ++- net/key/af_key.c | 3 ++- net/llc/af_llc.c | 5 ++++- net/netlink/af_netlink.c | 3 ++- net/netrom/af_netrom.c | 3 ++- net/packet/af_packet.c | 3 ++- net/phonet/af_phonet.c | 3 ++- net/rds/af_rds.c | 3 ++- net/rose/af_rose.c | 3 ++- net/rxrpc/af_rxrpc.c | 3 ++- net/socket.c | 2 +- net/tipc/socket.c | 6 ++++-- net/unix/af_unix.c | 3 ++- net/x25/af_x25.c | 3 ++- 37 files changed, 80 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 28182ed8dea..fcfe17a19a6 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -779,7 +779,7 @@ base_sock_create(struct net *net, struct socket *sock, int protocol) } static int -mISDN_sock_create(struct net *net, struct socket *sock, int proto) +mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern) { int err = -EPROTONOSUPPORT; diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index c14ee24c05a..ac806b27c65 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -104,7 +104,8 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) EXPORT_SYMBOL(pppox_ioctl); -static int pppox_create(struct net *net, struct socket *sock, int protocol) +static int pppox_create(struct net *net, struct socket *sock, int protocol, + int kern) { int rc = -EPROTOTYPE; diff --git a/include/linux/net.h b/include/linux/net.h index 4da9d571b05..70ee3c310f1 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -204,7 +204,8 @@ struct proto_ops { struct net_proto_family { int family; - int (*create)(struct net *net, struct socket *sock, int protocol); + int (*create)(struct net *net, struct socket *sock, + int protocol, int kern); struct module *owner; }; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index abe38014b7f..4b0ce2e2b46 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1021,7 +1021,8 @@ static struct proto ddp_proto = { * Create a socket. Initialise the socket, blank the addresses * set the state. */ -static int atalk_create(struct net *net, struct socket *sock, int protocol) +static int atalk_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; int rc = -ESOCKTNOSUPPORT; diff --git a/net/atm/pvc.c b/net/atm/pvc.c index a6e1fdbae87..8d74e62b0d7 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -127,7 +127,8 @@ static const struct proto_ops pvc_proto_ops = { }; -static int pvc_create(struct net *net, struct socket *sock,int protocol) +static int pvc_create(struct net *net, struct socket *sock, int protocol, + int kern) { if (net != &init_net) return -EAFNOSUPPORT; diff --git a/net/atm/svc.c b/net/atm/svc.c index 81935423331..c7395070ee7 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -25,7 +25,7 @@ #include "signaling.h" #include "addr.h" -static int svc_create(struct net *net, struct socket *sock,int protocol); +static int svc_create(struct net *net, struct socket *sock, int protocol, int kern); /* * Note: since all this is still nicely synchronized with the signaling demon, @@ -330,7 +330,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) lock_sock(sk); - error = svc_create(sock_net(sk), newsock,0); + error = svc_create(sock_net(sk), newsock, 0, 0); if (error) goto out; @@ -650,7 +650,8 @@ static const struct proto_ops svc_proto_ops = { }; -static int svc_create(struct net *net, struct socket *sock,int protocol) +static int svc_create(struct net *net, struct socket *sock, int protocol, + int kern) { int error; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index f1e998b2796..d6ddfa4c447 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -799,7 +799,8 @@ static struct proto ax25_proto = { .obj_size = sizeof(struct sock), }; -static int ax25_create(struct net *net, struct socket *sock, int protocol) +static int ax25_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; ax25_cb *ax25; diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 399e59c9c6c..087cc51f592 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -126,7 +126,8 @@ int bt_sock_unregister(int proto) } EXPORT_SYMBOL(bt_sock_unregister); -static int bt_sock_create(struct net *net, struct socket *sock, int proto) +static int bt_sock_create(struct net *net, struct socket *sock, int proto, + int kern) { int err; @@ -144,7 +145,7 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto) read_lock(&bt_proto_lock); if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { - err = bt_proto[proto]->create(net, sock, proto); + err = bt_proto[proto]->create(net, sock, proto, kern); bt_sock_reclassify_lock(sock, proto); module_put(bt_proto[proto]->owner); } diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 0a2c5460bb4..2ff6ac7b2ed 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -195,7 +195,8 @@ static struct proto bnep_proto = { .obj_size = sizeof(struct bt_sock) }; -static int bnep_sock_create(struct net *net, struct socket *sock, int protocol) +static int bnep_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index de7c8040bc5..978cc3a718a 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -190,7 +190,8 @@ static struct proto cmtp_proto = { .obj_size = sizeof(struct bt_sock) }; -static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol) +static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index e7395f23198..1ca5c7ca9bd 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -621,7 +621,8 @@ static struct proto hci_sk_proto = { .obj_size = sizeof(struct hci_pinfo) }; -static int hci_sock_create(struct net *net, struct socket *sock, int protocol) +static int hci_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 4beb6a7a295..9cfef68b9fe 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -241,7 +241,8 @@ static struct proto hidp_proto = { .obj_size = sizeof(struct bt_sock) }; -static int hidp_sock_create(struct net *net, struct socket *sock, int protocol) +static int hidp_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index d65101d92ee..365ae161d70 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -819,7 +819,8 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p return sk; } -static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol) +static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index d3bfc1b0afb..4b5968dda67 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -323,7 +323,8 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int return sk; } -static int rfcomm_sock_create(struct net *net, struct socket *sock, int protocol) +static int rfcomm_sock_create(struct net *net, struct socket *sock, + int protocol, int kern) { struct sock *sk; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 694a65541b7..dd8f6ec57dc 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -430,7 +430,8 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int pro return sk; } -static int sco_sock_create(struct net *net, struct socket *sock, int protocol) +static int sco_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/can/af_can.c b/net/can/af_can.c index 9c0426dc318..833bd838edc 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -114,7 +114,8 @@ static void can_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); } -static int can_create(struct net *net, struct socket *sock, int protocol) +static int can_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct can_proto *cp; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 2e355841ca9..9ade3a6de95 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -675,7 +675,8 @@ char *dn_addr2asc(__u16 addr, char *buf) -static int dn_create(struct net *net, struct socket *sock, int protocol) +static int dn_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 5e9426a11c3..596679803de 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -605,7 +605,8 @@ static struct proto econet_proto = { * Create an Econet socket */ -static int econet_create(struct net *net, struct socket *sock, int protocol) +static int econet_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct econet_sock *eo; diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 309348fba72..de6e34d2a7f 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -234,7 +234,7 @@ static const struct proto_ops ieee802154_dgram_ops = { * set the state. */ static int ieee802154_create(struct net *net, struct socket *sock, - int protocol) + int protocol, int kern) { struct sock *sk; int rc; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 180ec4c9491..5c7e42c02af 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -262,7 +262,8 @@ static inline int inet_netns_ok(struct net *net, int protocol) * Create an inet socket. */ -static int inet_create(struct net *net, struct socket *sock, int protocol) +static int inet_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct inet_protosw *answer; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 1b388935659..45ed5e05ab3 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -95,7 +95,8 @@ static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) return (struct ipv6_pinfo *)(((u8 *)sk) + offset); } -static int inet6_create(struct net *net, struct socket *sock, int protocol) +static int inet6_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct inet_sock *inet; struct ipv6_pinfo *np; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 6481ee4bdf7..96d193a2441 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1352,7 +1352,8 @@ static struct proto ipx_proto = { .obj_size = sizeof(struct ipx_sock), }; -static int ipx_create(struct net *net, struct socket *sock, int protocol) +static int ipx_create(struct net *net, struct socket *sock, int protocol, + int kern) { int rc = -ESOCKTNOSUPPORT; struct sock *sk; diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 9429e4002bc..e73a0016c0a 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -61,7 +61,7 @@ #include -static int irda_create(struct net *net, struct socket *sock, int protocol); +static int irda_create(struct net *net, struct socket *sock, int protocol, int kern); static const struct proto_ops irda_stream_ops; static const struct proto_ops irda_seqpacket_ops; @@ -839,7 +839,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) IRDA_DEBUG(2, "%s()\n", __func__); - err = irda_create(sock_net(sk), newsock, sk->sk_protocol); + err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0); if (err) return err; @@ -1062,7 +1062,8 @@ static struct proto irda_proto = { * Create IrDA socket * */ -static int irda_create(struct net *net, struct socket *sock, int protocol) +static int irda_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct irda_sock *self; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 3aebabb158a..1e428863574 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -481,7 +481,8 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) } /* Create an IUCV socket */ -static int iucv_sock_create(struct net *net, struct socket *sock, int protocol) +static int iucv_sock_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/key/af_key.c b/net/key/af_key.c index 472f6594184..86b2c22d091 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -177,7 +177,8 @@ static struct proto key_proto = { .obj_size = sizeof(struct pfkey_sock), }; -static int pfkey_create(struct net *net, struct socket *sock, int protocol) +static int pfkey_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); struct sock *sk; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 4866b4fb0c2..5266c286b26 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -140,14 +140,17 @@ static struct proto llc_proto = { /** * llc_ui_create - alloc and init a new llc_ui socket + * @net: network namespace (must be default network) * @sock: Socket to initialize and attach allocated sk to. * @protocol: Unused. + * @kern: on behalf of kernel or userspace * * Allocate and initialize a new llc_ui socket, validate the user wants a * socket type we have available. * Returns 0 upon success, negative upon failure. */ -static int llc_ui_create(struct net *net, struct socket *sock, int protocol) +static int llc_ui_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; int rc = -ESOCKTNOSUPPORT; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 0cd2d882931..aea805c98da 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -428,7 +428,8 @@ static int __netlink_create(struct net *net, struct socket *sock, return 0; } -static int netlink_create(struct net *net, struct socket *sock, int protocol) +static int netlink_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct module *module = NULL; struct mutex *cb_mutex; diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 281fa597cae..4bdd5697f63 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -425,7 +425,8 @@ static struct proto nr_proto = { .obj_size = sizeof(struct nr_sock), }; -static int nr_create(struct net *net, struct socket *sock, int protocol) +static int nr_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct nr_sock *nr; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 91d246d3478..3304caa6534 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1344,7 +1344,8 @@ static struct proto packet_proto = { * Create a packet of type SOCK_PACKET. */ -static int packet_create(struct net *net, struct socket *sock, int protocol) +static int packet_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct packet_sock *po; diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 66737aa995e..3bd1be6b26f 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -60,7 +60,8 @@ static inline void phonet_proto_put(struct phonet_protocol *pp) /* protocol family functions */ -static int pn_socket_create(struct net *net, struct socket *sock, int protocol) +static int pn_socket_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct pn_sock *pn; diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 2b978dc6e75..e25d8d5ce8d 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -410,7 +410,8 @@ static int __rds_create(struct socket *sock, struct sock *sk, int protocol) return 0; } -static int rds_create(struct net *net, struct socket *sock, int protocol) +static int rds_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index c17734c2ce8..4de4287fec3 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -512,7 +512,8 @@ static struct proto rose_proto = { .obj_size = sizeof(struct rose_sock), }; -static int rose_create(struct net *net, struct socket *sock, int protocol) +static int rose_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct rose_sock *rose; diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 6817c9781ef..f978d02a248 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -608,7 +608,8 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock, /* * create an RxRPC socket */ -static int rxrpc_create(struct net *net, struct socket *sock, int protocol) +static int rxrpc_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct rxrpc_sock *rx; struct sock *sk; diff --git a/net/socket.c b/net/socket.c index 9dff31c9b79..4f3e0f0c156 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1252,7 +1252,7 @@ static int __sock_create(struct net *net, int family, int type, int protocol, /* Now protected by module ref count */ rcu_read_unlock(); - err = pf->create(net, sock, protocol); + err = pf->create(net, sock, protocol, kern); if (err < 0) goto out_module_put; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e6d9abf7440..d00c2119faf 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -177,6 +177,7 @@ static void reject_rx_queue(struct sock *sk) * @net: network namespace (must be default network) * @sock: pre-allocated socket structure * @protocol: protocol indicator (must be 0) + * @kern: caused by kernel or by userspace? * * This routine creates additional data structures used by the TIPC socket, * initializes them, and links them together. @@ -184,7 +185,8 @@ static void reject_rx_queue(struct sock *sk) * Returns 0 on success, errno otherwise */ -static int tipc_create(struct net *net, struct socket *sock, int protocol) +static int tipc_create(struct net *net, struct socket *sock, int protocol, + int kern) { const struct proto_ops *ops; socket_state state; @@ -1528,7 +1530,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) buf = skb_peek(&sk->sk_receive_queue); - res = tipc_create(sock_net(sock->sk), new_sock, 0); + res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); if (!res) { struct sock *new_sk = new_sock->sk; struct tipc_sock *new_tsock = tipc_sk(new_sk); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3291902f0b8..178d3af2a60 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -621,7 +621,8 @@ out: return sk; } -static int unix_create(struct net *net, struct socket *sock, int protocol) +static int unix_create(struct net *net, struct socket *sock, int protocol, + int kern) { if (protocol && protocol != PF_UNIX) return -EPROTONOSUPPORT; diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index e19d811788a..38e235f61e2 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -501,7 +501,8 @@ out: return sk; } -static int x25_create(struct net *net, struct socket *sock, int protocol) +static int x25_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; struct x25_sock *x25; -- cgit v1.2.3 From c84b3268da3b85c9d8a9e504e1001a14ed829e94 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 5 Nov 2009 20:45:52 -0800 Subject: net: check kern before calling security subsystem Before calling capable(CAP_NET_RAW) check if this operations is on behalf of the kernel or on behalf of userspace. Do not do the security check if it is on behalf of the kernel. Signed-off-by: Eric Paris Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/bluetooth/l2cap.c | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv6/af_inet6.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 365ae161d70..ff0233df624 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -832,7 +832,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) return -EPERM; sock->ops = &l2cap_sock_ops; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 5c7e42c02af..7d12c6a9b19 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -326,7 +326,7 @@ lookup_protocol: } err = -EPERM; - if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) goto out_rcu_unlock; err = -EAFNOSUPPORT; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 45ed5e05ab3..12e69d364dd 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -159,7 +159,7 @@ lookup_protocol: } err = -EPERM; - if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) goto out_rcu_unlock; sock->ops = answer->ops; -- cgit v1.2.3 From 31ef30c760f7ddb133fa538df1dfbec1f42294d7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 20:47:35 -0800 Subject: bridge: remove dev_put() in add_del_if() add_del_if() is called with RTNL, we can use __dev_get_by_index() instead of [dev_get_by_index() + dev_put()] Signed-off-by: Eric Dumazet Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 6a6433daaf2..2af6e4a9026 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -81,6 +81,7 @@ static int get_fdb_entries(struct net_bridge *br, void __user *userbuf, return num; } +/* called with RTNL */ static int add_del_if(struct net_bridge *br, int ifindex, int isadd) { struct net_device *dev; @@ -89,7 +90,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - dev = dev_get_by_index(dev_net(br->dev), ifindex); + dev = __dev_get_by_index(dev_net(br->dev), ifindex); if (dev == NULL) return -EINVAL; @@ -98,7 +99,6 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd) else ret = br_del_if(br, dev); - dev_put(dev); return ret; } -- cgit v1.2.3 From 122ec6ffca3967ffaa96a4c7a5dc9cd71866e0bc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 20:53:47 -0800 Subject: netlabel: remove dev_put() calls Use dev_get_by_name_rcu() to avoid dev_put() calls, in sections already inside a rcu_read_lock() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/netlabel/netlabel_unlabeled.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index fb357f01018..3dfe2bac862 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -472,13 +472,12 @@ int netlbl_unlhsh_add(struct net *net, rcu_read_lock(); if (dev_name != NULL) { - dev = dev_get_by_name(net, dev_name); + dev = dev_get_by_name_rcu(net, dev_name); if (dev == NULL) { ret_val = -ENODEV; goto unlhsh_add_return; } ifindex = dev->ifindex; - dev_put(dev); iface = netlbl_unlhsh_search_iface(ifindex); } else { ifindex = 0; @@ -737,13 +736,12 @@ int netlbl_unlhsh_remove(struct net *net, rcu_read_lock(); if (dev_name != NULL) { - dev = dev_get_by_name(net, dev_name); + dev = dev_get_by_name_rcu(net, dev_name); if (dev == NULL) { ret_val = -ENODEV; goto unlhsh_remove_return; } iface = netlbl_unlhsh_search_iface(dev->ifindex); - dev_put(dev); } else iface = rcu_dereference(netlbl_unlhsh_def); if (iface == NULL) { -- cgit v1.2.3 From 40c9c31e388bfd513269df737f874d0cd53c1616 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 20:56:46 -0800 Subject: sctp: ipv6: avoid touching device refcount Avoid touching device refcount in sctp/ipv6, thanks to RCU Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index bacd6a7318b..cc50fbe9929 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -837,15 +837,16 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; - dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); - if (!dev) - return 0; - if (!ipv6_chk_addr(&init_net, &addr->v6.sin6_addr, + rcu_read_lock(); + dev = dev_get_by_index_rcu(&init_net, + addr->v6.sin6_scope_id); + if (!dev || + !ipv6_chk_addr(&init_net, &addr->v6.sin6_addr, dev, 0)) { - dev_put(dev); + rcu_read_unlock(); return 0; } - dev_put(dev); + rcu_read_unlock(); } else if (type == IPV6_ADDR_MAPPED) { if (!opt->v4mapped) return 0; @@ -873,10 +874,12 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr) if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; - dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); + rcu_read_lock(); + dev = dev_get_by_index_rcu(&init_net, + addr->v6.sin6_scope_id); + rcu_read_unlock(); if (!dev) return 0; - dev_put(dev); } af = opt->pf->af; } -- cgit v1.2.3 From bd27a8750c9b849068d80e298f99940bb7128b33 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 20:57:26 -0800 Subject: net_cls: Use __dev_get_by_index() We hold RTNL in tc_dump_tfilter(), we can avoid dev_hold()/dev_put() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/cls_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 7cf6c0fbc7a..c024da77824 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -404,6 +404,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER); } +/* called with RTNL */ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); @@ -422,7 +423,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return skb->len; - if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return skb->len; if (!tcm->tcm_parent) @@ -484,7 +485,6 @@ errout: if (cl) cops->put(q, cl); out: - dev_put(dev); return skb->len; } -- cgit v1.2.3 From 69df9d5993bd7dd7499ad0e98fe824147fbe5667 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 20:59:47 -0800 Subject: ip_frag: dont touch device refcount When sending fragmentation expiration ICMP V4/V6 messages, we can avoid touching device refcount, thanks to RCU Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 7 ++++--- net/ipv6/reassembly.c | 13 ++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 575f9bd51cc..b007f8af6e1 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -206,10 +206,11 @@ static void ip_expire(unsigned long arg) struct sk_buff *head = qp->q.fragments; /* Send an ICMP "Fragment Reassembly Timeout" message. */ - if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) { + rcu_read_lock(); + head->dev = dev_get_by_index_rcu(net, qp->iif); + if (head->dev) icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); - dev_put(head->dev); - } + rcu_read_unlock(); } out: spin_unlock(&qp->q.lock); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index da5bd0ed83d..dce699fb267 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -208,18 +208,17 @@ static void ip6_frag_expire(unsigned long data) fq_kill(fq); net = container_of(fq->q.net, struct net, ipv6.frags); - dev = dev_get_by_index(net, fq->iif); + rcu_read_lock(); + dev = dev_get_by_index_rcu(net, fq->iif); if (!dev) - goto out; + goto out_rcu_unlock; - rcu_read_lock(); IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); - rcu_read_unlock(); /* Don't send error if the first segment did not arrive. */ if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) - goto out; + goto out_rcu_unlock; /* But use as source device on which LAST ARRIVED @@ -228,9 +227,9 @@ static void ip6_frag_expire(unsigned long data) */ fq->q.fragments->dev = dev; icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); +out_rcu_unlock: + rcu_read_unlock(); out: - if (dev) - dev_put(dev); spin_unlock(&fq->q.lock); fq_put(fq); } -- cgit v1.2.3 From bf8e56bfc4fcfcef9f08e6233dc619706807893a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 21:03:39 -0800 Subject: net: sock_bindtodevice() RCU-ification Avoid dev_hold()/dev_put() in sock_bindtodevice() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/core/sock.c b/net/core/sock.c index 5a51512f638..38820eaecd4 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -420,14 +420,16 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) if (devname[0] == '\0') { index = 0; } else { - struct net_device *dev = dev_get_by_name(net, devname); + struct net_device *dev; + rcu_read_lock(); + dev = dev_get_by_name_rcu(net, devname); + if (dev) + index = dev->ifindex; + rcu_read_unlock(); ret = -ENODEV; if (!dev) goto out; - - index = dev->ifindex; - dev_put(dev); } lock_sock(sk); -- cgit v1.2.3 From baac8564547ac7f944af1c2e8cc6fdd57f2836a4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 21:04:32 -0800 Subject: pktgen: tx_bytes might be slightly wrong cur_pkt_size can be changed in proc fs while pktgen is running, we better use a private field to get precise tx-bytes counter. Signed-off-by: Ben Greear Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/pktgen.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 5ce017bf4af..d38470a3279 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -340,6 +340,7 @@ struct pktgen_dev { __u16 cur_udp_src; __u16 cur_queue_map; __u32 cur_pkt_size; + __u32 last_pkt_size; __u8 hh[14]; /* = { @@ -3434,7 +3435,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->clone_count--; /* back out increment, OOM */ return; } - + pkt_dev->last_pkt_size = pkt_dev->skb->len; pkt_dev->allocated_skbs++; pkt_dev->clone_count = 0; /* reset counter */ } @@ -3461,7 +3462,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->last_ok = 1; pkt_dev->sofar++; pkt_dev->seq_num++; - pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; + pkt_dev->tx_bytes += pkt_dev->last_pkt_size; break; default: /* Drivers are not supposed to return other values! */ if (net_ratelimit()) -- cgit v1.2.3 From 000ba2e43f33901859fd794bb33c885909d53b3b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 5 Nov 2009 22:37:11 -0800 Subject: net: Fix build warning in sock_bindtodevice(). net/core/sock.c: In function 'sock_setsockopt': net/core/sock.c:396: warning: 'index' may be used uninitialized in this function net/core/sock.c:396: note: 'index' was declared here GCC can't see that all paths initialize index, so just set it to the default (0) and eliminate the specific code block that handles the null device name string. Signed-off-by: David S. Miller --- net/core/sock.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/sock.c b/net/core/sock.c index 38820eaecd4..76ff58d43e2 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -417,9 +417,8 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) if (copy_from_user(devname, optval, optlen)) goto out; - if (devname[0] == '\0') { - index = 0; - } else { + index = 0; + if (devname[0] != '\0') { struct net_device *dev; rcu_read_lock(); -- cgit v1.2.3 From 1c889f4db6b2f8f8429e62011ba622642faba019 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 15 Sep 2009 16:57:04 +0400 Subject: wpan-phy: add wpan-phy iteration functions Add API to iterate over the wpan-phy instances. Signed-off-by: Dmitry Eremin-Solenikov --- include/net/wpan-phy.h | 2 ++ net/ieee802154/wpan-class.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'net') diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h index 5e803a0e4e7..3367dd95cf8 100644 --- a/include/net/wpan-phy.h +++ b/include/net/wpan-phy.h @@ -48,6 +48,8 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size); int wpan_phy_register(struct device *parent, struct wpan_phy *phy); void wpan_phy_unregister(struct wpan_phy *phy); void wpan_phy_free(struct wpan_phy *phy); +/* Same semantics as for class_for_each_device */ +int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), void *data); static inline void *wpan_phy_priv(struct wpan_phy *phy) { diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index f306604da67..0cec1384291 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -91,6 +91,31 @@ struct wpan_phy *wpan_phy_find(const char *str) } EXPORT_SYMBOL(wpan_phy_find); +struct wpan_phy_iter_data { + int (*fn)(struct wpan_phy *phy, void *data); + void *data; +}; + +static int wpan_phy_iter(struct device *dev, void *_data) +{ + struct wpan_phy_iter_data *wpid = _data; + struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); + return wpid->fn(phy, wpid->data); +} + +int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), + void *data) +{ + struct wpan_phy_iter_data wpid = { + .fn = fn, + .data = data, + }; + + return class_for_each_device(&wpan_phy_class, NULL, + &wpid, wpan_phy_iter); +} +EXPORT_SYMBOL(wpan_phy_for_each); + static int wpan_phy_idx_valid(int idx) { return idx >= 0; -- cgit v1.2.3 From 37eb0edc8488fccbf601ab3e7e582373ed2a631e Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 18 Sep 2009 16:35:06 +0400 Subject: wpan-phy: init channel/page fields Set page to zero (for compatibility w/ devices supporting only first page). Also init channel by default to -1 to disallow transfers for non-initialised devices. Signed-off-by: Dmitry Eremin-Solenikov --- net/ieee802154/wpan-class.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 0cec1384291..a10ae5be6ad 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -143,6 +143,9 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size) phy->dev.class = &wpan_phy_class; + phy->current_channel = -1; /* not initialised */ + phy->current_page = 0; /* for compatibility */ + return phy; } EXPORT_SYMBOL(wpan_phy_alloc); -- cgit v1.2.3 From 375bb0e04b618d0c425b0ea492d16cf71eb94905 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 28 Sep 2009 18:58:32 +0400 Subject: wpan-phy: use snprintf to limit the amount of chars written Use snprintf to limit the amount of chars put in the buffer for attr -> show. Signed-off-by: Dmitry Eremin-Solenikov --- net/ieee802154/wpan-class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index a10ae5be6ad..68ccde63155 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -30,7 +30,7 @@ static ssize_t name ## _show(struct device *dev, \ int ret; \ \ mutex_lock(&phy->pib_lock); \ - ret = sprintf(buf, format_string "\n", args); \ + ret = snprintf(buf, PAGE_SIZE, format_string "\n", args); \ mutex_unlock(&phy->pib_lock); \ return ret; \ } -- cgit v1.2.3 From a0b4a738e0e03f5e0d6ca366560f9a48e5adf83a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 22 Sep 2009 15:26:48 +0400 Subject: wpan-phy: allow specifying a per-page channel mask IEEE 802.15.4-2006 defines channel pages that hold channels (max 32 pages, 27 channels per page). Allow the driver to specify supported channels on pages, other than the first one. Signed-off-by: Dmitry Eremin-Solenikov --- drivers/ieee802154/fakehard.c | 2 +- include/net/wpan-phy.h | 2 +- net/ieee802154/wpan-class.c | 20 +++++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index 96a2959ce87..f6f2afefaa1 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -356,7 +356,7 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev) dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - phy->channels_supported = (1 << 27) - 1; + phy->channels_supported[0] = (1 << 27) - 1; phy->transmit_power = 0xbf; dev->netdev_ops = &fake_ops; diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h index 3367dd95cf8..7b7fc581e67 100644 --- a/include/net/wpan-phy.h +++ b/include/net/wpan-phy.h @@ -34,7 +34,7 @@ struct wpan_phy { */ u8 current_channel; u8 current_page; - u32 channels_supported; + u32 channels_supported[32]; u8 transmit_power; u8 cca_mode; diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 68ccde63155..0c51f85aa59 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -40,12 +40,30 @@ static ssize_t name ## _show(struct device *dev, \ MASTER_SHOW(current_channel, "%d"); MASTER_SHOW(current_page, "%d"); -MASTER_SHOW(channels_supported, "%#x"); MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB", ((signed char) (phy->transmit_power << 2)) >> 2, (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1 ); MASTER_SHOW(cca_mode, "%d"); +static ssize_t channels_supported_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); + int ret; + int i, len = 0; + + mutex_lock(&phy->pib_lock); + for (i = 0; i < 32; i++) { + ret = snprintf(buf + len, PAGE_SIZE - len, + "%#09x\n", phy->channels_supported[i]); + if (ret < 0) + break; + len += ret; + } + mutex_unlock(&phy->pib_lock); + return len; +} + static struct device_attribute pmib_attrs[] = { __ATTR_RO(current_channel), __ATTR_RO(current_page), -- cgit v1.2.3 From e9cf356c0c6b975fda84b15a5abdd1db88d74f84 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 28 Sep 2009 19:01:20 +0400 Subject: wpan-phy: follow usual patter of devices registration Follow the usual pattern of devices registration by adding new function (wpan_phy_set_dev) that sets child->parent relationship and removing parent argument from wpan_phy_register call. Signed-off-by: Dmitry Eremin-Solenikov --- drivers/ieee802154/fakehard.c | 3 ++- include/net/wpan-phy.h | 6 +++++- net/ieee802154/wpan-class.c | 4 +--- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index f6f2afefaa1..4ea93cc7afc 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -372,11 +372,12 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev) goto out; } + wpan_phy_set_dev(phy, &pdev->dev); SET_NETDEV_DEV(dev, &phy->dev); platform_set_drvdata(pdev, dev); - err = wpan_phy_register(&pdev->dev, phy); + err = wpan_phy_register(phy); if (err) goto out; diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h index 7b7fc581e67..f63537c1736 100644 --- a/include/net/wpan-phy.h +++ b/include/net/wpan-phy.h @@ -45,7 +45,11 @@ struct wpan_phy { }; struct wpan_phy *wpan_phy_alloc(size_t priv_size); -int wpan_phy_register(struct device *parent, struct wpan_phy *phy); +static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev) +{ + phy->dev.parent = dev; +} +int wpan_phy_register(struct wpan_phy *phy); void wpan_phy_unregister(struct wpan_phy *phy); void wpan_phy_free(struct wpan_phy *phy); /* Same semantics as for class_for_each_device */ diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 0c51f85aa59..cd42e88b839 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -168,10 +168,8 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size) } EXPORT_SYMBOL(wpan_phy_alloc); -int wpan_phy_register(struct device *parent, struct wpan_phy *phy) +int wpan_phy_register(struct wpan_phy *phy) { - phy->dev.parent = parent; - return device_add(&phy->dev); } EXPORT_SYMBOL(wpan_phy_register); -- cgit v1.2.3 From cb6b3763571570ebde1e82524c8a45a4275c8f11 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 10 Sep 2009 17:50:12 +0400 Subject: ieee802154: merge nl802154 and wpan-class in single module There is no real need to have ieee802154 interfaces separate into several small modules, as neither of them has it's own use. Signed-off-by: Dmitry Eremin-Solenikov --- net/ieee802154/Makefile | 4 ++-- net/ieee802154/netlink.c | 9 ++------- net/ieee802154/wpan-class.c | 23 ++++++++++++++++++++--- 3 files changed, 24 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 4068a9f5113..42b1f0dc138 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,5 +1,5 @@ -obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o wpan-class.o -nl802154-y := netlink.o nl_policy.o +obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o +ieee802154-y := netlink.o nl_policy.o wpan-class.o af_802154-y := af_ieee802154.o raw.o dgram.o ccflags-y += -Wall -DDEBUG diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index ca767bde17a..0fadd6bd77f 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -643,7 +643,7 @@ static struct genl_ops ieee802154_coordinator_ops[] = { ieee802154_dump_iface), }; -static int __init ieee802154_nl_init(void) +int __init ieee802154_nl_init(void) { int rc; int i; @@ -676,14 +676,9 @@ fail: genl_unregister_family(&ieee802154_coordinator_family); return rc; } -module_init(ieee802154_nl_init); -static void __exit ieee802154_nl_exit(void) +void __exit ieee802154_nl_exit(void) { genl_unregister_family(&ieee802154_coordinator_family); } -module_exit(ieee802154_nl_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ieee 802.15.4 configuration interface"); diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index cd42e88b839..38bac70cca1 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -22,6 +22,8 @@ #include +#include "ieee802154.h" + #define MASTER_SHOW_COMPLEX(name, format_string, args...) \ static ssize_t name ## _show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -188,16 +190,31 @@ EXPORT_SYMBOL(wpan_phy_free); static int __init wpan_phy_class_init(void) { - return class_register(&wpan_phy_class); + int rc; + rc = class_register(&wpan_phy_class); + if (rc) + goto err; + + rc = ieee802154_nl_init(); + if (rc) + goto err_nl; + + return 0; +err_nl: + class_unregister(&wpan_phy_class); +err: + return rc; } -subsys_initcall(wpan_phy_class_init); +module_init(wpan_phy_class_init); static void __exit wpan_phy_class_exit(void) { + ieee802154_nl_exit(); class_unregister(&wpan_phy_class); } module_exit(wpan_phy_class_exit); -MODULE_DESCRIPTION("IEEE 802.15.4 device class"); MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("IEEE 802.15.4 configuration interface"); +MODULE_AUTHOR("Dmitry Eremin-Solenikov"); -- cgit v1.2.3 From 78fe738d1a631ec34a29d830880e38f5c14c1371 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 14 Sep 2009 18:17:36 +0400 Subject: ieee802154: split away MAC commands implementation Move all mac-related stuff to separate file so that ieee802154/netlink.c contains only generic code. Signed-off-by: Dmitry Eremin-Solenikov --- net/ieee802154/Makefile | 2 +- net/ieee802154/ieee802154.h | 48 ++++ net/ieee802154/netlink.c | 605 +------------------------------------------ net/ieee802154/nl-mac.c | 609 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 669 insertions(+), 595 deletions(-) create mode 100644 net/ieee802154/ieee802154.h create mode 100644 net/ieee802154/nl-mac.c (limited to 'net') diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 42b1f0dc138..69af9f6a404 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o -ieee802154-y := netlink.o nl_policy.o wpan-class.o +ieee802154-y := netlink.o nl-mac.o nl_policy.o wpan-class.o af_802154-y := af_ieee802154.o raw.o dgram.o ccflags-y += -Wall -DDEBUG diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h new file mode 100644 index 00000000000..0790eb06d68 --- /dev/null +++ b/net/ieee802154/ieee802154.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef IEEE_802154_LOCAL_H +#define IEEE_802154_LOCAL_H + +int __init ieee802154_nl_init(void); +void __exit ieee802154_nl_exit(void); + +#define IEEE802154_OP(_cmd, _func) \ + { \ + .cmd = _cmd, \ + .policy = ieee802154_policy, \ + .doit = _func, \ + .dumpit = NULL, \ + .flags = GENL_ADMIN_PERM, \ + } + +#define IEEE802154_DUMP(_cmd, _func, _dump) \ + { \ + .cmd = _cmd, \ + .policy = ieee802154_policy, \ + .doit = _func, \ + .dumpit = _dump, \ + } + +struct sk_buff *ieee802154_nl_create(int flags, u8 req); +int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group); + +extern struct genl_family nl802154_family; +int nl802154_mac_register(void); +int nl802154_phy_register(void); + +#endif diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 0fadd6bd77f..5b738ec7d9f 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -23,21 +23,15 @@ */ #include -#include -#include -#include #include -#include #include -#include -#include -#include -#include + +#include "ieee802154.h" static unsigned int ieee802154_seq_num; static DEFINE_SPINLOCK(ieee802154_seq_lock); -static struct genl_family ieee802154_coordinator_family = { +struct genl_family nl802154_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = IEEE802154_NL_NAME, @@ -45,16 +39,8 @@ static struct genl_family ieee802154_coordinator_family = { .maxattr = IEEE802154_ATTR_MAX, }; -static struct genl_multicast_group ieee802154_coord_mcgrp = { - .name = IEEE802154_MCAST_COORD_NAME, -}; - -static struct genl_multicast_group ieee802154_beacon_mcgrp = { - .name = IEEE802154_MCAST_BEACON_NAME, -}; - /* Requests to userspace */ -static struct sk_buff *ieee802154_nl_create(int flags, u8 req) +struct sk_buff *ieee802154_nl_create(int flags, u8 req) { void *hdr; struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); @@ -65,7 +51,7 @@ static struct sk_buff *ieee802154_nl_create(int flags, u8 req) spin_lock_irqsave(&ieee802154_seq_lock, f); hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, - &ieee802154_coordinator_family, flags, req); + &nl802154_family, flags, req); spin_unlock_irqrestore(&ieee802154_seq_lock, f); if (!hdr) { nlmsg_free(msg); @@ -75,7 +61,7 @@ static struct sk_buff *ieee802154_nl_create(int flags, u8 req) return msg; } -static int ieee802154_nl_finish(struct sk_buff *msg) +int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group) { /* XXX: nlh is right at the start of msg */ void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); @@ -83,602 +69,33 @@ static int ieee802154_nl_finish(struct sk_buff *msg) if (genlmsg_end(msg, hdr) < 0) goto out; - return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, - GFP_ATOMIC); + return genlmsg_multicast(msg, 0, group, GFP_ATOMIC); out: nlmsg_free(msg); return -ENOBUFS; } -int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 cap) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - if (addr->addr_type != IEEE802154_ADDR_LONG) { - pr_err("%s: received non-long source address!\n", __func__); - return -EINVAL; - } - - msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); - if (!msg) - return -ENOBUFS; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - - NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, - addr->hwaddr); - - NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap); - - return ieee802154_nl_finish(msg); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_assoc_indic); - -int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, - u8 status) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); - if (!msg) - return -ENOBUFS; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - - NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr); - NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); - - return ieee802154_nl_finish(msg); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); - -int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 reason) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); - if (!msg) - return -ENOBUFS; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - - if (addr->addr_type == IEEE802154_ADDR_LONG) - NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, - addr->hwaddr); - else - NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, - addr->short_addr); - - NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason); - - return ieee802154_nl_finish(msg); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); - -int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); - if (!msg) - return -ENOBUFS; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - - NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); - - return ieee802154_nl_finish(msg); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); - -int ieee802154_nl_beacon_indic(struct net_device *dev, - u16 panid, u16 coord_addr) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); - if (!msg) - return -ENOBUFS; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr); - NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid); - - return ieee802154_nl_finish(msg); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_beacon_indic); - -int ieee802154_nl_scan_confirm(struct net_device *dev, - u8 status, u8 scan_type, u32 unscanned, u8 page, - u8 *edl/* , struct list_head *pan_desc_list */) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); - if (!msg) - return -ENOBUFS; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - - NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); - NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); - NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); - NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page); - - if (edl) - NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); - - return ieee802154_nl_finish(msg); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_scan_confirm); - -int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) -{ - struct sk_buff *msg; - - pr_debug("%s\n", __func__); - - msg = ieee802154_nl_create(0, IEEE802154_START_CONF); - if (!msg) - return -ENOBUFS; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - - NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); - - return ieee802154_nl_finish(msg); - -nla_put_failure: - nlmsg_free(msg); - return -ENOBUFS; -} -EXPORT_SYMBOL(ieee802154_nl_start_confirm); - -static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, - u32 seq, int flags, struct net_device *dev) -{ - void *hdr; - - pr_debug("%s\n", __func__); - - hdr = genlmsg_put(msg, 0, seq, &ieee802154_coordinator_family, flags, - IEEE802154_LIST_IFACE); - if (!hdr) - goto out; - - NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); - NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); - - NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, - dev->dev_addr); - NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, - ieee802154_mlme_ops(dev)->get_short_addr(dev)); - NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, - ieee802154_mlme_ops(dev)->get_pan_id(dev)); - return genlmsg_end(msg, hdr); - -nla_put_failure: - genlmsg_cancel(msg, hdr); -out: - return -EMSGSIZE; -} - -/* Requests from userspace */ -static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) -{ - struct net_device *dev; - - if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { - char name[IFNAMSIZ + 1]; - nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], - sizeof(name)); - dev = dev_get_by_name(&init_net, name); - } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) - dev = dev_get_by_index(&init_net, - nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); - else - return NULL; - - if (!dev) - return NULL; - - if (dev->type != ARPHRD_IEEE802154) { - dev_put(dev); - return NULL; - } - - return dev; -} - -static int ieee802154_associate_req(struct sk_buff *skb, - struct genl_info *info) -{ - struct net_device *dev; - struct ieee802154_addr addr; - u8 page; - int ret = -EINVAL; - - if (!info->attrs[IEEE802154_ATTR_CHANNEL] || - !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || - (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && - !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || - !info->attrs[IEEE802154_ATTR_CAPABILITY]) - return -EINVAL; - - dev = ieee802154_nl_get_dev(info); - if (!dev) - return -ENODEV; - - if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { - addr.addr_type = IEEE802154_ADDR_LONG; - nla_memcpy(addr.hwaddr, - info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], - IEEE802154_ADDR_LEN); - } else { - addr.addr_type = IEEE802154_ADDR_SHORT; - addr.short_addr = nla_get_u16( - info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); - } - addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); - - if (info->attrs[IEEE802154_ATTR_PAGE]) - page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); - else - page = 0; - - ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, - nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), - page, - nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); - - dev_put(dev); - return ret; -} - -static int ieee802154_associate_resp(struct sk_buff *skb, - struct genl_info *info) -{ - struct net_device *dev; - struct ieee802154_addr addr; - int ret = -EINVAL; - - if (!info->attrs[IEEE802154_ATTR_STATUS] || - !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || - !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) - return -EINVAL; - - dev = ieee802154_nl_get_dev(info); - if (!dev) - return -ENODEV; - - addr.addr_type = IEEE802154_ADDR_LONG; - nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], - IEEE802154_ADDR_LEN); - addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - - - ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, - nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), - nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); - - dev_put(dev); - return ret; -} - -static int ieee802154_disassociate_req(struct sk_buff *skb, - struct genl_info *info) -{ - struct net_device *dev; - struct ieee802154_addr addr; - int ret = -EINVAL; - - if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && - !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || - !info->attrs[IEEE802154_ATTR_REASON]) - return -EINVAL; - - dev = ieee802154_nl_get_dev(info); - if (!dev) - return -ENODEV; - - if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { - addr.addr_type = IEEE802154_ADDR_LONG; - nla_memcpy(addr.hwaddr, - info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], - IEEE802154_ADDR_LEN); - } else { - addr.addr_type = IEEE802154_ADDR_SHORT; - addr.short_addr = nla_get_u16( - info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); - } - addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - - ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, - nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); - - dev_put(dev); - return ret; -} - -/* - * PANid, channel, beacon_order = 15, superframe_order = 15, - * PAN_coordinator, battery_life_extension = 0, - * coord_realignment = 0, security_enable = 0 -*/ -static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) -{ - struct net_device *dev; - struct ieee802154_addr addr; - - u8 channel, bcn_ord, sf_ord; - u8 page; - int pan_coord, blx, coord_realign; - int ret; - - if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || - !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || - !info->attrs[IEEE802154_ATTR_CHANNEL] || - !info->attrs[IEEE802154_ATTR_BCN_ORD] || - !info->attrs[IEEE802154_ATTR_SF_ORD] || - !info->attrs[IEEE802154_ATTR_PAN_COORD] || - !info->attrs[IEEE802154_ATTR_BAT_EXT] || - !info->attrs[IEEE802154_ATTR_COORD_REALIGN] - ) - return -EINVAL; - - dev = ieee802154_nl_get_dev(info); - if (!dev) - return -ENODEV; - - addr.addr_type = IEEE802154_ADDR_SHORT; - addr.short_addr = nla_get_u16( - info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); - addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); - - channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); - bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); - sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); - pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); - blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); - coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); - - if (info->attrs[IEEE802154_ATTR_PAGE]) - page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); - else - page = 0; - - - if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { - ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); - dev_put(dev); - return -EINVAL; - } - - ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, - bcn_ord, sf_ord, pan_coord, blx, coord_realign); - - dev_put(dev); - return ret; -} - -static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) -{ - struct net_device *dev; - int ret; - u8 type; - u32 channels; - u8 duration; - u8 page; - - if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || - !info->attrs[IEEE802154_ATTR_CHANNELS] || - !info->attrs[IEEE802154_ATTR_DURATION]) - return -EINVAL; - - dev = ieee802154_nl_get_dev(info); - if (!dev) - return -ENODEV; - - type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); - channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); - duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); - - if (info->attrs[IEEE802154_ATTR_PAGE]) - page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); - else - page = 0; - - - ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, - duration); - - dev_put(dev); - return ret; -} - -static int ieee802154_list_iface(struct sk_buff *skb, - struct genl_info *info) -{ - /* Request for interface name, index, type, IEEE address, - PAN Id, short address */ - struct sk_buff *msg; - struct net_device *dev = NULL; - int rc = -ENOBUFS; - - pr_debug("%s\n", __func__); - - dev = ieee802154_nl_get_dev(info); - if (!dev) - return -ENODEV; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - goto out_dev; - - rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq, - 0, dev); - if (rc < 0) - goto out_free; - - dev_put(dev); - - return genlmsg_unicast(&init_net, msg, info->snd_pid); -out_free: - nlmsg_free(msg); -out_dev: - dev_put(dev); - return rc; - -} - -static int ieee802154_dump_iface(struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - struct net_device *dev; - int idx; - int s_idx = cb->args[0]; - - pr_debug("%s\n", __func__); - - idx = 0; - for_each_netdev(net, dev) { - if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) - goto cont; - - if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) - break; -cont: - idx++; - } - cb->args[0] = idx; - - return skb->len; -} - -#define IEEE802154_OP(_cmd, _func) \ - { \ - .cmd = _cmd, \ - .policy = ieee802154_policy, \ - .doit = _func, \ - .dumpit = NULL, \ - .flags = GENL_ADMIN_PERM, \ - } - -#define IEEE802154_DUMP(_cmd, _func, _dump) \ - { \ - .cmd = _cmd, \ - .policy = ieee802154_policy, \ - .doit = _func, \ - .dumpit = _dump, \ - } - -static struct genl_ops ieee802154_coordinator_ops[] = { - IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), - IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), - IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), - IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), - IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), - IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, - ieee802154_dump_iface), -}; - int __init ieee802154_nl_init(void) { int rc; - int i; - rc = genl_register_family(&ieee802154_coordinator_family); + rc = genl_register_family(&nl802154_family); if (rc) goto fail; - rc = genl_register_mc_group(&ieee802154_coordinator_family, - &ieee802154_coord_mcgrp); + rc = nl802154_mac_register(); if (rc) goto fail; - rc = genl_register_mc_group(&ieee802154_coordinator_family, - &ieee802154_beacon_mcgrp); - if (rc) - goto fail; - - - for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { - rc = genl_register_ops(&ieee802154_coordinator_family, - &ieee802154_coordinator_ops[i]); - if (rc) - goto fail; - } - return 0; fail: - genl_unregister_family(&ieee802154_coordinator_family); + genl_unregister_family(&nl802154_family); return rc; } void __exit ieee802154_nl_exit(void) { - genl_unregister_family(&ieee802154_coordinator_family); + genl_unregister_family(&nl802154_family); } diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c new file mode 100644 index 00000000000..e8816bf7c31 --- /dev/null +++ b/net/ieee802154/nl-mac.c @@ -0,0 +1,609 @@ +/* + * Netlink inteface for IEEE 802.15.4 stack + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + * Maxim Osipov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee802154.h" + +static struct genl_multicast_group ieee802154_coord_mcgrp = { + .name = IEEE802154_MCAST_COORD_NAME, +}; + +static struct genl_multicast_group ieee802154_beacon_mcgrp = { + .name = IEEE802154_MCAST_BEACON_NAME, +}; + +int ieee802154_nl_assoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 cap) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + if (addr->addr_type != IEEE802154_ADDR_LONG) { + pr_err("%s: received non-long source address!\n", __func__); + return -EINVAL; + } + + msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, + addr->hwaddr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap); + + return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_assoc_indic); + +int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, + u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr); + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); + +int ieee802154_nl_disassoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + if (addr->addr_type == IEEE802154_ADDR_LONG) + NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, + addr->hwaddr); + else + NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, + addr->short_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason); + + return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); + +int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); + +int ieee802154_nl_beacon_indic(struct net_device *dev, + u16 panid, u16 coord_addr) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid); + + return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_beacon_indic); + +int ieee802154_nl_scan_confirm(struct net_device *dev, + u8 status, u8 scan_type, u32 unscanned, u8 page, + u8 *edl/* , struct list_head *pan_desc_list */) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); + NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); + NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page); + + if (edl) + NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); + + return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_scan_confirm); + +int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_START_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_start_confirm); + +static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, + u32 seq, int flags, struct net_device *dev) +{ + void *hdr; + + pr_debug("%s\n", __func__); + + hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, + IEEE802154_LIST_IFACE); + if (!hdr) + goto out; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, + ieee802154_mlme_ops(dev)->get_short_addr(dev)); + NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, + ieee802154_mlme_ops(dev)->get_pan_id(dev)); + return genlmsg_end(msg, hdr); + +nla_put_failure: + genlmsg_cancel(msg, hdr); +out: + return -EMSGSIZE; +} + +/* Requests from userspace */ +static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) +{ + struct net_device *dev; + + if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { + char name[IFNAMSIZ + 1]; + nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], + sizeof(name)); + dev = dev_get_by_name(&init_net, name); + } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) + dev = dev_get_by_index(&init_net, + nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); + else + return NULL; + + if (!dev) + return NULL; + + if (dev->type != ARPHRD_IEEE802154) { + dev_put(dev); + return NULL; + } + + return dev; +} + +static int ieee802154_associate_req(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + u8 page; + int ret = -EINVAL; + + if (!info->attrs[IEEE802154_ATTR_CHANNEL] || + !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || + (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && + !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || + !info->attrs[IEEE802154_ATTR_CAPABILITY]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, + info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], + IEEE802154_ADDR_LEN); + } else { + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); + } + addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + + if (info->attrs[IEEE802154_ATTR_PAGE]) + page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); + else + page = 0; + + ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, + nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), + page, + nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); + + dev_put(dev); + return ret; +} + +static int ieee802154_associate_resp(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if (!info->attrs[IEEE802154_ATTR_STATUS] || + !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || + !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], + IEEE802154_ADDR_LEN); + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + + + ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, + nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), + nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); + + dev_put(dev); + return ret; +} + +static int ieee802154_disassociate_req(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && + !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || + !info->attrs[IEEE802154_ATTR_REASON]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, + info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], + IEEE802154_ADDR_LEN); + } else { + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); + } + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + + ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, + nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); + + dev_put(dev); + return ret; +} + +/* + * PANid, channel, beacon_order = 15, superframe_order = 15, + * PAN_coordinator, battery_life_extension = 0, + * coord_realignment = 0, security_enable = 0 +*/ +static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + + u8 channel, bcn_ord, sf_ord; + u8 page; + int pan_coord, blx, coord_realign; + int ret; + + if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || + !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || + !info->attrs[IEEE802154_ATTR_CHANNEL] || + !info->attrs[IEEE802154_ATTR_BCN_ORD] || + !info->attrs[IEEE802154_ATTR_SF_ORD] || + !info->attrs[IEEE802154_ATTR_PAN_COORD] || + !info->attrs[IEEE802154_ATTR_BAT_EXT] || + !info->attrs[IEEE802154_ATTR_COORD_REALIGN] + ) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); + addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + + channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); + bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); + sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); + pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); + blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); + coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); + + if (info->attrs[IEEE802154_ATTR_PAGE]) + page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); + else + page = 0; + + + if (addr.short_addr == IEEE802154_ADDR_BROADCAST) { + ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS); + dev_put(dev); + return -EINVAL; + } + + ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page, + bcn_ord, sf_ord, pan_coord, blx, coord_realign); + + dev_put(dev); + return ret; +} + +static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev; + int ret; + u8 type; + u32 channels; + u8 duration; + u8 page; + + if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || + !info->attrs[IEEE802154_ATTR_CHANNELS] || + !info->attrs[IEEE802154_ATTR_DURATION]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); + channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); + duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); + + if (info->attrs[IEEE802154_ATTR_PAGE]) + page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]); + else + page = 0; + + + ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, + duration); + + dev_put(dev); + return ret; +} + +static int ieee802154_list_iface(struct sk_buff *skb, + struct genl_info *info) +{ + /* Request for interface name, index, type, IEEE address, + PAN Id, short address */ + struct sk_buff *msg; + struct net_device *dev = NULL; + int rc = -ENOBUFS; + + pr_debug("%s\n", __func__); + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto out_dev; + + rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq, + 0, dev); + if (rc < 0) + goto out_free; + + dev_put(dev); + + return genlmsg_reply(msg, info); +out_free: + nlmsg_free(msg); +out_dev: + dev_put(dev); + return rc; + +} + +static int ieee802154_dump_iface(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + int idx; + int s_idx = cb->args[0]; + + pr_debug("%s\n", __func__); + + idx = 0; + for_each_netdev(net, dev) { + if (idx < s_idx || (dev->type != ARPHRD_IEEE802154)) + goto cont; + + if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) + break; +cont: + idx++; + } + cb->args[0] = idx; + + return skb->len; +} + +static struct genl_ops ieee802154_coordinator_ops[] = { + IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), + IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), + IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), + IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), + IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), + IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, + ieee802154_dump_iface), +}; + +/* + * No need to unregister as family unregistration will do it. + */ +int nl802154_mac_register(void) +{ + int i; + int rc; + + rc = genl_register_mc_group(&nl802154_family, + &ieee802154_coord_mcgrp); + if (rc) + return rc; + + rc = genl_register_mc_group(&nl802154_family, + &ieee802154_beacon_mcgrp); + if (rc) + return rc; + + for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { + rc = genl_register_ops(&nl802154_family, + &ieee802154_coordinator_ops[i]); + if (rc) + return rc; + } + + return 0; +} -- cgit v1.2.3 From 1eaa9d03d3ee9156c8c405b006ce892ae28290ad Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 15 Sep 2009 17:04:44 +0400 Subject: ieee802154: add LIST_PHY command support Add nl802154 command to get information about PHY's present in the system. Signed-off-by: Dmitry Eremin-Solenikov --- include/linux/nl802154.h | 4 + net/ieee802154/Makefile | 2 +- net/ieee802154/netlink.c | 4 + net/ieee802154/nl-phy.c | 188 +++++++++++++++++++++++++++++++++++++++++++++ net/ieee802154/nl_policy.c | 2 + 5 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 net/ieee802154/nl-phy.c (limited to 'net') diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index b7d9435d5a9..275fd94f472 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h @@ -65,6 +65,9 @@ enum { IEEE802154_ATTR_SEC, IEEE802154_ATTR_PAGE, + IEEE802154_ATTR_CHANNEL_PAGE_LIST, + + IEEE802154_ATTR_PHY_NAME, __IEEE802154_ATTR_MAX, }; @@ -114,6 +117,7 @@ enum { IEEE802154_RX_ENABLE_CONF, /* Not supported yet */ IEEE802154_LIST_IFACE, + IEEE802154_LIST_PHY, __IEEE802154_CMD_MAX, }; diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 69af9f6a404..ce2d3358285 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o -ieee802154-y := netlink.o nl-mac.o nl_policy.o wpan-class.o +ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o af_802154-y := af_ieee802154.o raw.o dgram.o ccflags-y += -Wall -DDEBUG diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 5b738ec7d9f..8a221737f75 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -87,6 +87,10 @@ int __init ieee802154_nl_init(void) if (rc) goto fail; + rc = nl802154_phy_register(); + if (rc) + goto fail; + return 0; fail: diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c new file mode 100644 index 00000000000..b7af722eb78 --- /dev/null +++ b/net/ieee802154/nl-phy.c @@ -0,0 +1,188 @@ +/* + * Netlink inteface for IEEE 802.15.4 stack + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + * Maxim Osipov + */ + +#include +#include +#include +#include +#include + +#include "ieee802154.h" + +static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 pid, + u32 seq, int flags, struct wpan_phy *phy) +{ + void *hdr; + int i, pages = 0; + uint32_t *buf = kzalloc(32 * sizeof(uint32_t), GFP_KERNEL); + + pr_debug("%s\n", __func__); + + if (!buf) + goto out; + + hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, + IEEE802154_LIST_PHY); + if (!hdr) + goto out; + + mutex_lock(&phy->pib_lock); + NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); + + NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, phy->current_page); + NLA_PUT_U8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel); + for (i = 0; i < 32; i++) { + if (phy->channels_supported[i]) + buf[pages++] = phy->channels_supported[i] | (i << 27); + } + if (pages) + NLA_PUT(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST, + pages * sizeof(uint32_t), buf); + + mutex_unlock(&phy->pib_lock); + return genlmsg_end(msg, hdr); + +nla_put_failure: + mutex_unlock(&phy->pib_lock); + genlmsg_cancel(msg, hdr); +out: + kfree(buf); + return -EMSGSIZE; +} + +static int ieee802154_list_phy(struct sk_buff *skb, + struct genl_info *info) +{ + /* Request for interface name, index, type, IEEE address, + PAN Id, short address */ + struct sk_buff *msg; + struct wpan_phy *phy; + const char *name; + int rc = -ENOBUFS; + + pr_debug("%s\n", __func__); + + if (!info->attrs[IEEE802154_ATTR_PHY_NAME]) + return -EINVAL; + + name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); + if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') + return -EINVAL; /* phy name should be null-terminated */ + + + phy = wpan_phy_find(name); + if (!phy) + return -ENODEV; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto out_dev; + + rc = ieee802154_nl_fill_phy(msg, info->snd_pid, info->snd_seq, + 0, phy); + if (rc < 0) + goto out_free; + + wpan_phy_put(phy); + + return genlmsg_reply(msg, info); +out_free: + nlmsg_free(msg); +out_dev: + wpan_phy_put(phy); + return rc; + +} + +struct dump_phy_data { + struct sk_buff *skb; + struct netlink_callback *cb; + int idx, s_idx; +}; + +static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) +{ + int rc; + struct dump_phy_data *data = _data; + + pr_debug("%s\n", __func__); + + if (data->idx++ < data->s_idx) + return 0; + + rc = ieee802154_nl_fill_phy(data->skb, + NETLINK_CB(data->cb->skb).pid, + data->cb->nlh->nlmsg_seq, + NLM_F_MULTI, + phy); + + if (rc < 0) { + data->idx--; + return rc; + } + + return 0; +} + +static int ieee802154_dump_phy(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct dump_phy_data data = { + .cb = cb, + .skb = skb, + .s_idx = cb->args[0], + .idx = 0, + }; + + pr_debug("%s\n", __func__); + + wpan_phy_for_each(ieee802154_dump_phy_iter, &data); + + cb->args[0] = data.idx; + + return skb->len; +} + +static struct genl_ops ieee802154_phy_ops[] = { + IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy, + ieee802154_dump_phy), +}; + +/* + * No need to unregister as family unregistration will do it. + */ +int nl802154_phy_register(void) +{ + int i; + int rc; + + for (i = 0; i < ARRAY_SIZE(ieee802154_phy_ops); i++) { + rc = genl_register_ops(&nl802154_family, + &ieee802154_phy_ops[i]); + if (rc) + return rc; + } + + return 0; +} diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c index 2363ebee02e..6adda4d46f9 100644 --- a/net/ieee802154/nl_policy.c +++ b/net/ieee802154/nl_policy.c @@ -27,6 +27,7 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { [IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, }, [IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, }, + [IEEE802154_ATTR_PHY_NAME] = { .type = NLA_STRING, }, [IEEE802154_ATTR_STATUS] = { .type = NLA_U8, }, [IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, @@ -50,5 +51,6 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { [IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, }, [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, + [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, }, }; -- cgit v1.2.3 From 339b4ca5f68c7fd02eae54e9ce49c4b5f5d8b545 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 4 Nov 2009 18:05:38 +0300 Subject: ieee802154: add two nl802154 helpers Add two nl802154 helpers: one for starting a reply message, one for sending. Signed-off-by: Dmitry Eremin-Solenikov --- net/ieee802154/ieee802154.h | 5 +++++ net/ieee802154/netlink.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'net') diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index 0790eb06d68..aadec428e6e 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h @@ -38,8 +38,13 @@ void __exit ieee802154_nl_exit(void); .dumpit = _dump, \ } +struct genl_info; + struct sk_buff *ieee802154_nl_create(int flags, u8 req); int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group); +struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, + int flags, u8 req); +int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info); extern struct genl_family nl802154_family; int nl802154_mac_register(void); diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 8a221737f75..33137b99e47 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -75,6 +75,39 @@ out: return -ENOBUFS; } +struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, + int flags, u8 req) +{ + void *hdr; + struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + + if (!msg) + return NULL; + + hdr = genlmsg_put_reply(msg, info, + &nl802154_family, flags, req); + if (!hdr) { + nlmsg_free(msg); + return NULL; + } + + return msg; +} + +int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info) +{ + /* XXX: nlh is right at the start of msg */ + void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); + + if (genlmsg_end(msg, hdr) < 0) + goto out; + + return genlmsg_reply(msg, info); +out: + nlmsg_free(msg); + return -ENOBUFS; +} + int __init ieee802154_nl_init(void) { int rc; -- cgit v1.2.3 From 0a868b26c8ba32f6988f87dd81697917a2f612b6 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 29 Oct 2009 16:28:52 +0300 Subject: ieee802154: add PHY_NAME to LIST_IFACE command results Signed-off-by: Dmitry Eremin-Solenikov --- net/ieee802154/nl-mac.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index e8816bf7c31..135c1678fb1 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "ieee802154.h" @@ -251,6 +252,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev) { void *hdr; + struct wpan_phy *phy; pr_debug("%s\n", __func__); @@ -259,7 +261,11 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, if (!hdr) goto out; + phy = ieee802154_mlme_ops(dev)->get_phy(dev); + BUG_ON(!phy); + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, @@ -268,9 +274,11 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid, ieee802154_mlme_ops(dev)->get_short_addr(dev)); NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID, ieee802154_mlme_ops(dev)->get_pan_id(dev)); + wpan_phy_put(phy); return genlmsg_end(msg, hdr); nla_put_failure: + wpan_phy_put(phy); genlmsg_cancel(msg, hdr); out: return -EMSGSIZE; -- cgit v1.2.3 From bb1cafb8fc414d6dbe933f888df6540c2ef02101 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 5 Nov 2009 16:56:23 +0300 Subject: ieee802154: add support for creation/removal of logic interfaces Add support for two more NL802154 commands: ADD_IFACE and DEL_IFACE, thus allowing creation and removal of logic WPAN interfaces on the top of wpan-phy. Signed-off-by: Dmitry Eremin-Solenikov --- include/linux/nl802154.h | 2 + include/net/wpan-phy.h | 4 ++ net/ieee802154/nl-phy.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) (limited to 'net') diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h index 275fd94f472..33d9f517510 100644 --- a/include/linux/nl802154.h +++ b/include/linux/nl802154.h @@ -118,6 +118,8 @@ enum { IEEE802154_LIST_IFACE, IEEE802154_LIST_PHY, + IEEE802154_ADD_IFACE, + IEEE802154_DEL_IFACE, __IEEE802154_CMD_MAX, }; diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h index a65e98509fb..85926231c07 100644 --- a/include/net/wpan-phy.h +++ b/include/net/wpan-phy.h @@ -41,6 +41,10 @@ struct wpan_phy { struct device dev; int idx; + struct net_device *(*add_iface)(struct wpan_phy *phy, + const char *name); + void (*del_iface)(struct wpan_phy *phy, struct net_device *dev); + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index b7af722eb78..199a2d9d12f 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include /* for rtnl_{un,}lock */ #include #include "ieee802154.h" @@ -164,9 +167,162 @@ static int ieee802154_dump_phy(struct sk_buff *skb, return skb->len; } +static int ieee802154_add_iface(struct sk_buff *skb, + struct genl_info *info) +{ + struct sk_buff *msg; + struct wpan_phy *phy; + const char *name; + const char *devname; + int rc = -ENOBUFS; + struct net_device *dev; + + pr_debug("%s\n", __func__); + + if (!info->attrs[IEEE802154_ATTR_PHY_NAME]) + return -EINVAL; + + name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); + if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') + return -EINVAL; /* phy name should be null-terminated */ + + if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { + devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); + if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] + != '\0') + return -EINVAL; /* phy name should be null-terminated */ + } else { + devname = "wpan%d"; + } + + if (strlen(devname) >= IFNAMSIZ) + return -ENAMETOOLONG; + + phy = wpan_phy_find(name); + if (!phy) + return -ENODEV; + + msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE); + if (!msg) + goto out_dev; + + if (!phy->add_iface) { + rc = -EINVAL; + goto nla_put_failure; + } + + dev = phy->add_iface(phy, devname); + if (IS_ERR(dev)) { + rc = PTR_ERR(dev); + goto nla_put_failure; + } + + NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + + dev_put(dev); + + wpan_phy_put(phy); + + return ieee802154_nl_reply(msg, info); + +nla_put_failure: + nlmsg_free(msg); +out_dev: + wpan_phy_put(phy); + return rc; +} + +static int ieee802154_del_iface(struct sk_buff *skb, + struct genl_info *info) +{ + struct sk_buff *msg; + struct wpan_phy *phy; + const char *name; + int rc; + struct net_device *dev; + + pr_debug("%s\n", __func__); + + if (!info->attrs[IEEE802154_ATTR_DEV_NAME]) + return -EINVAL; + + name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); + if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') + return -EINVAL; /* name should be null-terminated */ + + dev = dev_get_by_name(genl_info_net(info), name); + if (!dev) + return -ENODEV; + + phy = ieee802154_mlme_ops(dev)->get_phy(dev); + BUG_ON(!phy); + + rc = -EINVAL; + /* phy name is optional, but should be checked if it's given */ + if (info->attrs[IEEE802154_ATTR_PHY_NAME]) { + struct wpan_phy *phy2; + + const char *pname = + nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); + if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] + != '\0') + /* name should be null-terminated */ + goto out_dev; + + phy2 = wpan_phy_find(pname); + if (!phy2) + goto out_dev; + + if (phy != phy2) { + wpan_phy_put(phy2); + goto out_dev; + } + } + + rc = -ENOBUFS; + + msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE); + if (!msg) + goto out_dev; + + if (!phy->del_iface) { + rc = -EINVAL; + goto nla_put_failure; + } + + rtnl_lock(); + phy->del_iface(phy, dev); + + /* We don't have device anymore */ + dev_put(dev); + dev = NULL; + + rtnl_unlock(); + + + NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, name); + + wpan_phy_put(phy); + + return ieee802154_nl_reply(msg, info); + +nla_put_failure: + nlmsg_free(msg); +out_dev: + wpan_phy_put(phy); + if (dev) + dev_put(dev); + + return rc; +} + static struct genl_ops ieee802154_phy_ops[] = { IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy, ieee802154_dump_phy), + IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), + IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), }; /* -- cgit v1.2.3 From dee5817e88ac8195e5938d6671f434a071e35698 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Nov 2009 17:04:00 +0100 Subject: netfilter: remove unneccessary checks from netlink notifiers The NETLINK_URELEASE notifier is only invoked for bound sockets, so there is no need to check ->pid again. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ip_queue.c | 3 +-- net/ipv6/netfilter/ip6_queue.c | 3 +-- net/netfilter/nfnetlink_log.c | 3 +-- net/netfilter/nfnetlink_queue.c | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 9811a456fb5..9f078709195 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -497,8 +497,7 @@ ipq_rcv_nl_event(struct notifier_block *this, { struct netlink_notify *n = ptr; - if (event == NETLINK_URELEASE && - n->protocol == NETLINK_FIREWALL && n->pid) { + if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL) { write_lock_bh(&queue_lock); if ((n->net == &init_net) && (n->pid == peer_pid)) __ipq_reset(); diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index a82016fd5d6..47a3623e711 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -499,8 +499,7 @@ ipq_rcv_nl_event(struct notifier_block *this, { struct netlink_notify *n = ptr; - if (event == NETLINK_URELEASE && - n->protocol == NETLINK_IP6_FW && n->pid) { + if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) { write_lock_bh(&queue_lock); if ((n->net == &init_net) && (n->pid == peer_pid)) __ipq_reset(); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index f900dc3194a..3aa66b2f9e8 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -666,8 +666,7 @@ nfulnl_rcv_nl_event(struct notifier_block *this, { struct netlink_notify *n = ptr; - if (event == NETLINK_URELEASE && - n->protocol == NETLINK_NETFILTER && n->pid) { + if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { int i; /* destroy all instances for this pid */ diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 7a9dec9fb82..7e3fa410641 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -574,8 +574,7 @@ nfqnl_rcv_nl_event(struct notifier_block *this, { struct netlink_notify *n = ptr; - if (event == NETLINK_URELEASE && - n->protocol == NETLINK_NETFILTER && n->pid) { + if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { int i; /* destroy all instances for this pid */ -- cgit v1.2.3 From af81858172cc0f3da81946aab919c26e4b364efc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Nov 2009 11:35:50 +0100 Subject: mac80211: async station powersave handling Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 32 ++++++++++++ net/mac80211/debugfs_sta.c | 5 +- net/mac80211/main.c | 8 +-- net/mac80211/rx.c | 86 ++++++--------------------------- net/mac80211/sta_info.c | 118 ++++++++++++++++++++++++++++++++++++++++++++- net/mac80211/sta_info.h | 23 +++++++-- net/mac80211/tx.c | 13 +++-- 7 files changed, 200 insertions(+), 85 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7f035d779db..2c10eac637d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2136,6 +2136,38 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, const u8 *addr); +/** + * ieee80211_sta_block_awake - block station from waking up + * @hw: the hardware + * @pubsta: the station + * @block: whether to block or unblock + * + * Some devices require that all frames that are on the queues + * for a specific station that went to sleep are flushed before + * a poll response or frames after the station woke up can be + * delivered to that it. Note that such frames must be rejected + * by the driver as filtered, with the appropriate status flag. + * + * This function allows implementing this mode in a race-free + * manner. + * + * To do this, a driver must keep track of the number of frames + * still enqueued for a specific station. If this number is not + * zero when the station goes to sleep, the driver must call + * this function to force mac80211 to consider the station to + * be asleep regardless of the station's actual state. Once the + * number of outstanding frames reaches zero, the driver must + * call this function again to unblock the station. That will + * cause mac80211 to be able to send ps-poll responses, and if + * the station queried in the meantime then frames will also + * be sent out as a result of this. Additionally, the driver + * will be notified that the station woke up some time after + * it is unblocked, regardless of whether the station actually + * woke up while blocked or not. + */ +void ieee80211_sta_block_awake(struct ieee80211_hw *hw, + struct ieee80211_sta *pubsta, bool block); + /** * ieee80211_beacon_loss - inform hardware does not receive beacons * diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 4425b613552..f043c29070d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -66,10 +66,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, char buf[100]; struct sta_info *sta = file->private_data; u32 staflags = get_sta_flags(sta); - int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", + int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", staflags & WLAN_STA_AUTH ? "AUTH\n" : "", staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", - staflags & WLAN_STA_PS ? "PS\n" : "", + staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "", + staflags & WLAN_STA_PS_DRIVER ? "PS (driver)\n" : "", staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", staflags & WLAN_STA_WME ? "WME\n" : "", diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9e6703ff7fb..beb8718d905 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -385,13 +385,13 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * can be unknown, for example with different interrupt status * bits. */ - if (test_sta_flags(sta, WLAN_STA_PS) && + if (test_sta_flags(sta, WLAN_STA_PS_STA) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { skb_queue_tail(&sta->tx_filtered, skb); return; } - if (!test_sta_flags(sta, WLAN_STA_PS) && + if (!test_sta_flags(sta, WLAN_STA_PS_STA) && !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { /* Software retry the packet once */ info->flags |= IEEE80211_TX_INTFL_RETRIED; @@ -406,7 +406,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, "queue_len=%d PS=%d @%lu\n", wiphy_name(local->hw.wiphy), skb_queue_len(&sta->tx_filtered), - !!test_sta_flags(sta, WLAN_STA_PS), jiffies); + !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); #endif dev_kfree_skb(skb); } @@ -446,7 +446,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (sta) { if (!(info->flags & IEEE80211_TX_STAT_ACK) && - test_sta_flags(sta, WLAN_STA_PS)) { + test_sta_flags(sta, WLAN_STA_PS_STA)) { /* * The STA is in power save mode, so assume * that this TX packet failed because of that. diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c06496f0b76..28316b2a585 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -781,7 +781,7 @@ static void ap_sta_ps_start(struct sta_info *sta) struct ieee80211_local *local = sdata->local; atomic_inc(&sdata->bss->num_sta_ps); - set_sta_flags(sta, WLAN_STA_PS); + set_sta_flags(sta, WLAN_STA_PS_STA); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", @@ -792,33 +792,25 @@ static void ap_sta_ps_start(struct sta_info *sta) static void ap_sta_ps_end(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - struct ieee80211_local *local = sdata->local; - int sent, buffered; atomic_dec(&sdata->bss->num_sta_ps); - clear_sta_flags(sta, WLAN_STA_PS); - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); - - if (!skb_queue_empty(&sta->ps_tx_buf)) - sta_info_clear_tim_bit(sta); + clear_sta_flags(sta, WLAN_STA_PS_STA); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - /* Send all buffered frames to the station */ - sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); - buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); - sent += buffered; - local->total_ps_buffered -= buffered; - + if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " - "since STA not sleeping anymore\n", sdata->dev->name, - sta->sta.addr, sta->sta.aid, sent - buffered, buffered); + printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", + sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + return; + } + + ieee80211_sta_ps_deliver_wakeup(sta); } static ieee80211_rx_result debug_noinline @@ -866,7 +858,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!ieee80211_has_morefrags(hdr->frame_control) && (rx->sdata->vif.type == NL80211_IFTYPE_AP || rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { - if (test_sta_flags(sta, WLAN_STA_PS)) { + if (test_sta_flags(sta, WLAN_STA_PS_STA)) { /* * Ignore doze->wake transitions that are * indicated by non-data frames, the standard @@ -1094,9 +1086,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); - struct sk_buff *skb; - int no_pending_pkts; + struct ieee80211_sub_if_data *sdata = rx->sdata; __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || @@ -1107,56 +1097,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) return RX_DROP_UNUSABLE; - skb = skb_dequeue(&rx->sta->tx_filtered); - if (!skb) { - skb = skb_dequeue(&rx->sta->ps_tx_buf); - if (skb) - rx->local->total_ps_buffered--; - } - no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) && - skb_queue_empty(&rx->sta->ps_tx_buf); - - if (skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) skb->data; - - /* - * Tell TX path to send this frame even though the STA may - * still remain is PS mode after this frame exchange. - */ - info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; - -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", - rx->sta->sta.addr, rx->sta->sta.aid, - skb_queue_len(&rx->sta->ps_tx_buf)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - - /* Use MoreData flag to indicate whether there are more - * buffered frames for this STA */ - if (no_pending_pkts) - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); - else - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - - ieee80211_add_pending_skb(rx->local, skb); - - if (no_pending_pkts) - sta_info_clear_tim_bit(rx->sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - } else { - /* - * FIXME: This can be the result of a race condition between - * us expiring a frame and the station polling for it. - * Should we send it a null-func frame indicating we - * have nothing buffered for it? - */ - printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " - "though there are no buffered frames for it\n", - rx->dev->name, rx->sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - } + if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER)) + ieee80211_sta_ps_deliver_poll_response(rx->sta); + else + set_sta_flags(rx->sta, WLAN_STA_PSPOLL); /* Free PS Poll skb here instead of returning RX_DROP that would * count as an dropped frame. */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cde2da7a74d..be59456e8a4 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -171,6 +171,8 @@ void sta_info_destroy(struct sta_info *sta) local = sta->local; + cancel_work_sync(&sta->drv_unblock_wk); + rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); @@ -259,6 +261,21 @@ static void sta_info_hash_add(struct ieee80211_local *local, rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); } +static void sta_unblock(struct work_struct *wk) +{ + struct sta_info *sta; + + sta = container_of(wk, struct sta_info, drv_unblock_wk); + + if (sta->dead) + return; + + if (!test_sta_flags(sta, WLAN_STA_PS_STA)) + ieee80211_sta_ps_deliver_wakeup(sta); + else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) + ieee80211_sta_ps_deliver_poll_response(sta); +} + struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, gfp_t gfp) { @@ -272,6 +289,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, spin_lock_init(&sta->lock); spin_lock_init(&sta->flaglock); + INIT_WORK(&sta->drv_unblock_wk, sta_unblock); memcpy(sta->sta.addr, addr, ETH_ALEN); sta->local = local; @@ -478,8 +496,10 @@ static void __sta_info_unlink(struct sta_info **sta) } list_del(&(*sta)->list); + (*sta)->dead = true; - if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { + if (test_and_clear_sta_flags(*sta, + WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { BUG_ON(!sdata->bss); atomic_dec(&sdata->bss->num_sta_ps); @@ -825,3 +845,99 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); } EXPORT_SYMBOL(ieee80211_find_sta); + +/* powersave support code */ +void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + int sent, buffered; + + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); + + if (!skb_queue_empty(&sta->ps_tx_buf)) + sta_info_clear_tim_bit(sta); + + /* Send all buffered frames to the station */ + sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); + buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); + sent += buffered; + local->total_ps_buffered -= buffered; + +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " + "since STA not sleeping anymore\n", sdata->dev->name, + sta->sta.addr, sta->sta.aid, sent - buffered, buffered); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ +} + +void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + int no_pending_pkts; + + skb = skb_dequeue(&sta->tx_filtered); + if (!skb) { + skb = skb_dequeue(&sta->ps_tx_buf); + if (skb) + local->total_ps_buffered--; + } + no_pending_pkts = skb_queue_empty(&sta->tx_filtered) && + skb_queue_empty(&sta->ps_tx_buf); + + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) skb->data; + + /* + * Tell TX path to send this frame even though the STA may + * still remain is PS mode after this frame exchange. + */ + info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; + +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", + sta->sta.addr, sta->sta.aid, + skb_queue_len(&sta->ps_tx_buf)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + + /* Use MoreData flag to indicate whether there are more + * buffered frames for this STA */ + if (no_pending_pkts) + hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); + else + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + + ieee80211_add_pending_skb(local, skb); + + if (no_pending_pkts) + sta_info_clear_tim_bit(sta); +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + } else { + /* + * FIXME: This can be the result of a race condition between + * us expiring a frame and the station polling for it. + * Should we send it a null-func frame indicating we + * have nothing buffered for it? + */ + printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " + "though there are no buffered frames for it\n", + sdata->dev->name, sta->sta.addr); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + } +} + +void ieee80211_sta_block_awake(struct ieee80211_hw *hw, + struct ieee80211_sta *pubsta, bool block) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + + if (block) + set_sta_flags(sta, WLAN_STA_PS_DRIVER); + else + ieee80211_queue_work(hw, &sta->drv_unblock_wk); +} +EXPORT_SYMBOL(ieee80211_sta_block_awake); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 703f5492ee6..4673454176e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "key.h" /** @@ -21,7 +22,7 @@ * * @WLAN_STA_AUTH: Station is authenticated. * @WLAN_STA_ASSOC: Station is associated. - * @WLAN_STA_PS: Station is in power-save mode + * @WLAN_STA_PS_STA: Station is in power-save mode * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic. * This bit is always checked so needs to be enabled for all stations * when virtual port control is not in use. @@ -36,11 +37,16 @@ * @WLAN_STA_MFP: Management frame protection is used with this STA. * @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle. * Used to deny ADDBA requests (both TX and RX). + * @WLAN_STA_PS_DRIVER: driver requires keeping this station in + * power-save mode logically to flush frames that might still + * be in the queues + * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping + * station in power-save mode, reply when the driver unblocks. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, WLAN_STA_ASSOC = 1<<1, - WLAN_STA_PS = 1<<2, + WLAN_STA_PS_STA = 1<<2, WLAN_STA_AUTHORIZED = 1<<3, WLAN_STA_SHORT_PREAMBLE = 1<<4, WLAN_STA_ASSOC_AP = 1<<5, @@ -48,7 +54,9 @@ enum ieee80211_sta_info_flags { WLAN_STA_WDS = 1<<7, WLAN_STA_CLEAR_PS_FILT = 1<<9, WLAN_STA_MFP = 1<<10, - WLAN_STA_SUSPEND = 1<<11 + WLAN_STA_SUSPEND = 1<<11, + WLAN_STA_PS_DRIVER = 1<<12, + WLAN_STA_PSPOLL = 1<<13, }; #define STA_TID_NUM 16 @@ -216,6 +224,8 @@ struct sta_ampdu_mlme { * @plink_timer_was_running: used by suspend/resume to restore timers * @debugfs: debug filesystem info * @sta: station information we share with the driver + * @dead: set to true when sta is unlinked + * @drv_unblock_wk used for driver PS unblocking */ struct sta_info { /* General information, mostly static */ @@ -229,8 +239,12 @@ struct sta_info { spinlock_t lock; spinlock_t flaglock; + struct work_struct drv_unblock_wk; + u16 listen_interval; + bool dead; + /* * for use by the internal lifetime management, * see __sta_info_unlink @@ -430,4 +444,7 @@ int sta_info_flush(struct ieee80211_local *local, void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); +void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); +void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); + #endif /* STA_INFO_H */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c7dc8ccff5b..bfaa43e096d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -374,7 +374,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) staflags = get_sta_flags(sta); - if (unlikely((staflags & WLAN_STA_PS) && + if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) && !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " @@ -397,8 +397,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) } else tx->local->total_ps_buffered++; - /* Queue frame to be sent after STA sends an PS Poll frame */ - if (skb_queue_empty(&sta->ps_tx_buf)) + /* + * Queue frame to be sent after STA wakes up/polls, + * but don't set the TIM bit if the driver is blocking + * wakeup or poll response transmissions anyway. + */ + if (skb_queue_empty(&sta->ps_tx_buf) && + !(staflags & WLAN_STA_PS_DRIVER)) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; @@ -408,7 +413,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { + else if (unlikely(staflags & WLAN_STA_PS_STA)) { printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, sta->sta.addr); -- cgit v1.2.3 From 7a229387d317df525ebd19e146493db7f2694b8b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Nov 2009 23:00:29 -0800 Subject: net: copy socket ioctl code to net/socket.h This makes an identical copy of the socket compat_ioctl code from fs/compat_ioctl.c to net/socket.c, as a preparation for moving the functionality in a way that can be easily reviewed. The code is hidden inside of #if 0 and gets activated in the patch that will make it work. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- net/socket.c | 716 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 716 insertions(+) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index 4f3e0f0c156..344bd230b83 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2459,6 +2459,722 @@ void socket_seq_show(struct seq_file *seq) #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_COMPAT +#if 0 +static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct compat_timeval __user *up = compat_ptr(arg); + mm_segment_t old_fs = get_fs(); + struct timeval ktv; + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&ktv); + set_fs(old_fs); + if (!err) { + err = put_user(ktv.tv_sec, &up->tv_sec); + err |= __put_user(ktv.tv_usec, &up->tv_usec); + } + return err; +} + +static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct compat_timespec __user *up = compat_ptr(arg); + mm_segment_t old_fs = get_fs(); + struct timespec kts; + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&kts); + set_fs(old_fs); + if (!err) { + err = put_user(kts.tv_sec, &up->tv_sec); + err |= __put_user(kts.tv_nsec, &up->tv_nsec); + } + return err; +} + +struct ifmap32 { + compat_ulong_t mem_start; + compat_ulong_t mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq32 { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + compat_int_t ifru_ivalue; + compat_int_t ifru_mtu; + struct ifmap32 ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; + compat_caddr_t ifru_data; + /* XXXX? ifru_settings should be here */ + } ifr_ifru; +}; + +struct ifconf32 { + compat_int_t ifc_len; /* size of buffer */ + compat_caddr_t ifcbuf; +}; + +static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq __user *uifr; + int err; + + uifr = compat_alloc_user_space(sizeof(struct ifreq)); + if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32))) + return -EFAULT; + + err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr); + if (err) + return err; + + if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32))) + return -EFAULT; + + return 0; +} + +static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifconf32 ifc32; + struct ifconf ifc; + struct ifconf __user *uifc; + struct ifreq32 __user *ifr32; + struct ifreq __user *ifr; + unsigned int i, j; + int err; + + if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32))) + return -EFAULT; + + if (ifc32.ifcbuf == 0) { + ifc32.ifc_len = 0; + ifc.ifc_len = 0; + ifc.ifc_req = NULL; + uifc = compat_alloc_user_space(sizeof(struct ifconf)); + } else { + size_t len =((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * + sizeof (struct ifreq); + uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); + ifc.ifc_len = len; + ifr = ifc.ifc_req = (void __user *)(uifc + 1); + ifr32 = compat_ptr(ifc32.ifcbuf); + for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { + if (copy_in_user(ifr, ifr32, sizeof(struct ifreq32))) + return -EFAULT; + ifr++; + ifr32++; + } + } + if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) + return -EFAULT; + + err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)uifc); + if (err) + return err; + + if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) + return -EFAULT; + + ifr = ifc.ifc_req; + ifr32 = compat_ptr(ifc32.ifcbuf); + for (i = 0, j = 0; + i + sizeof (struct ifreq32) <= ifc32.ifc_len && j < ifc.ifc_len; + i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { + if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) + return -EFAULT; + ifr32++; + ifr++; + } + + if (ifc32.ifcbuf == 0) { + /* Translate from 64-bit structure multiple to + * a 32-bit one. + */ + i = ifc.ifc_len; + i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); + ifc32.ifc_len = i; + } else { + ifc32.ifc_len = i; + } + if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) + return -EFAULT; + + return 0; +} + +static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq __user *ifr; + struct ifreq32 __user *ifr32; + u32 data; + void __user *datap; + + ifr = compat_alloc_user_space(sizeof(*ifr)); + ifr32 = compat_ptr(arg); + + if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) + return -EFAULT; + + if (get_user(data, &ifr32->ifr_ifru.ifru_data)) + return -EFAULT; + + datap = compat_ptr(data); + if (put_user(datap, &ifr->ifr_ifru.ifru_data)) + return -EFAULT; + + return sys_ioctl(fd, cmd, (unsigned long) ifr); +} + +static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq kifr; + struct ifreq __user *uifr; + struct ifreq32 __user *ifr32 = compat_ptr(arg); + mm_segment_t old_fs; + int err; + u32 data; + void __user *datap; + + switch (cmd) { + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDCHANGEACTIVE: + if (copy_from_user(&kifr, ifr32, sizeof(struct ifreq32))) + return -EFAULT; + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&kifr); + set_fs (old_fs); + + return err; + case SIOCBONDSLAVEINFOQUERY: + case SIOCBONDINFOQUERY: + uifr = compat_alloc_user_space(sizeof(*uifr)); + if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) + return -EFAULT; + + if (get_user(data, &ifr32->ifr_ifru.ifru_data)) + return -EFAULT; + + datap = compat_ptr(data); + if (put_user(datap, &uifr->ifr_ifru.ifru_data)) + return -EFAULT; + + return sys_ioctl (fd, cmd, (unsigned long)uifr); + default: + return -EINVAL; + }; +} + +static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq __user *u_ifreq64; + struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); + char tmp_buf[IFNAMSIZ]; + void __user *data64; + u32 data32; + + if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), + IFNAMSIZ)) + return -EFAULT; + if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) + return -EFAULT; + data64 = compat_ptr(data32); + + u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); + + /* Don't check these user accesses, just let that get trapped + * in the ioctl handler instead. + */ + if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], + IFNAMSIZ)) + return -EFAULT; + if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) + return -EFAULT; + + return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); +} + +static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + struct ifreq32 __user *uifr32; + struct ifmap32 __user *uifmap32; + mm_segment_t old_fs; + int err; + + uifr32 = compat_ptr(arg); + uifmap32 = &uifr32->ifr_ifru.ifru_map; + switch (cmd) { + case SIOCSIFMAP: + err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); + err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); + err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); + err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); + err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq); + err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma); + err |= __get_user(ifr.ifr_map.port, &uifmap32->port); + if (err) + return -EFAULT; + break; + case SIOCSHWTSTAMP: + if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) + return -EFAULT; + ifr.ifr_data = compat_ptr(uifr32->ifr_ifru.ifru_data); + break; + default: + if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) + return -EFAULT; + break; + } + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + switch (cmd) { + case SIOCGIFFLAGS: + case SIOCGIFMETRIC: + case SIOCGIFMTU: + case SIOCGIFMEM: + case SIOCGIFHWADDR: + case SIOCGIFINDEX: + case SIOCGIFADDR: + case SIOCGIFBRDADDR: + case SIOCGIFDSTADDR: + case SIOCGIFNETMASK: + case SIOCGIFTXQLEN: + if (copy_to_user(uifr32, &ifr, sizeof(*uifr32))) + return -EFAULT; + break; + case SIOCGIFMAP: + err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); + err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); + err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); + err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); + err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq); + err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma); + err |= __put_user(ifr.ifr_map.port, &uifmap32->port); + if (err) + err = -EFAULT; + break; + } + } + return err; +} + +struct rtentry32 { + u32 rt_pad1; + struct sockaddr rt_dst; /* target address */ + struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct sockaddr rt_genmask; /* target network mask (IP) */ + unsigned short rt_flags; + short rt_pad2; + u32 rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short rt_pad4; + short rt_metric; /* +1 for binary compatibility! */ + /* char * */ u32 rt_dev; /* forcing the device at add */ + u32 rt_mtu; /* per route MTU/Window */ + u32 rt_window; /* Window clamping */ + unsigned short rt_irtt; /* Initial RTT */ +}; + +struct in6_rtmsg32 { + struct in6_addr rtmsg_dst; + struct in6_addr rtmsg_src; + struct in6_addr rtmsg_gateway; + u32 rtmsg_type; + u16 rtmsg_dst_len; + u16 rtmsg_src_len; + u32 rtmsg_metric; + u32 rtmsg_info; + u32 rtmsg_flags; + s32 rtmsg_ifindex; +}; + +static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + int ret; + void *r = NULL; + struct in6_rtmsg r6; + struct rtentry r4; + char devname[16]; + u32 rtdev; + mm_segment_t old_fs = get_fs(); + + struct socket *mysock = sockfd_lookup(fd, &ret); + + if (mysock && mysock->sk && mysock->sk->sk_family == AF_INET6) { /* ipv6 */ + struct in6_rtmsg32 __user *ur6 = compat_ptr(arg); + ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst), + 3 * sizeof(struct in6_addr)); + ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type)); + ret |= __get_user (r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); + ret |= __get_user (r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); + ret |= __get_user (r6.rtmsg_metric, &(ur6->rtmsg_metric)); + ret |= __get_user (r6.rtmsg_info, &(ur6->rtmsg_info)); + ret |= __get_user (r6.rtmsg_flags, &(ur6->rtmsg_flags)); + ret |= __get_user (r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); + + r = (void *) &r6; + } else { /* ipv4 */ + struct rtentry32 __user *ur4 = compat_ptr(arg); + ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst), + 3 * sizeof(struct sockaddr)); + ret |= __get_user (r4.rt_flags, &(ur4->rt_flags)); + ret |= __get_user (r4.rt_metric, &(ur4->rt_metric)); + ret |= __get_user (r4.rt_mtu, &(ur4->rt_mtu)); + ret |= __get_user (r4.rt_window, &(ur4->rt_window)); + ret |= __get_user (r4.rt_irtt, &(ur4->rt_irtt)); + ret |= __get_user (rtdev, &(ur4->rt_dev)); + if (rtdev) { + ret |= copy_from_user (devname, compat_ptr(rtdev), 15); + r4.rt_dev = devname; devname[15] = 0; + } else + r4.rt_dev = NULL; + + r = (void *) &r4; + } + + if (ret) { + ret = -EFAULT; + goto out; + } + + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, cmd, (unsigned long) r); + set_fs (old_fs); + +out: + if (mysock) + sockfd_put(mysock); + + return ret; +} + +/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE + * for some operations; this forces use of the newer bridge-utils that + * use compatiable ioctls + */ +static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + u32 tmp; + + if (get_user(tmp, (u32 __user *) arg)) + return -EFAULT; + if (tmp == BRCTL_GET_VERSION) + return BRCTL_VERSION + 1; + return -EINVAL; +} + +struct atmif_sioc32 { + compat_int_t number; + compat_int_t length; + compat_caddr_t arg; +}; + +struct atm_iobuf32 { + compat_int_t length; + compat_caddr_t buffer; +}; + +#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) +#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) +#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) +#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) +#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) +#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) +#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) +#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) +#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) +#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) +#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) +#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) +#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) +#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) +#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) +#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) +#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} atm_ioctl_map[] = { + { ATM_GETLINKRATE32, ATM_GETLINKRATE }, + { ATM_GETNAMES32, ATM_GETNAMES }, + { ATM_GETTYPE32, ATM_GETTYPE }, + { ATM_GETESI32, ATM_GETESI }, + { ATM_GETADDR32, ATM_GETADDR }, + { ATM_RSTADDR32, ATM_RSTADDR }, + { ATM_ADDADDR32, ATM_ADDADDR }, + { ATM_DELADDR32, ATM_DELADDR }, + { ATM_GETCIRANGE32, ATM_GETCIRANGE }, + { ATM_SETCIRANGE32, ATM_SETCIRANGE }, + { ATM_SETESI32, ATM_SETESI }, + { ATM_SETESIF32, ATM_SETESIF }, + { ATM_GETSTAT32, ATM_GETSTAT }, + { ATM_GETSTATZ32, ATM_GETSTATZ }, + { ATM_GETLOOP32, ATM_GETLOOP }, + { ATM_SETLOOP32, ATM_SETLOOP }, + { ATM_QUERYLOOP32, ATM_QUERYLOOP } +}; + +#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map) + +static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct atm_iobuf __user *iobuf; + struct atm_iobuf32 __user *iobuf32; + u32 data; + void __user *datap; + int len, err; + + iobuf = compat_alloc_user_space(sizeof(*iobuf)); + iobuf32 = compat_ptr(arg); + + if (get_user(len, &iobuf32->length) || + get_user(data, &iobuf32->buffer)) + return -EFAULT; + datap = compat_ptr(data); + if (put_user(len, &iobuf->length) || + put_user(datap, &iobuf->buffer)) + return -EFAULT; + + err = sys_ioctl(fd, cmd, (unsigned long)iobuf); + + if (!err) { + if (copy_in_user(&iobuf32->length, &iobuf->length, + sizeof(int))) + err = -EFAULT; + } + + return err; +} + +static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct atmif_sioc __user *sioc; + struct atmif_sioc32 __user *sioc32; + u32 data; + void __user *datap; + int err; + + sioc = compat_alloc_user_space(sizeof(*sioc)); + sioc32 = compat_ptr(arg); + + if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) || + get_user(data, &sioc32->arg)) + return -EFAULT; + datap = compat_ptr(data); + if (put_user(datap, &sioc->arg)) + return -EFAULT; + + err = sys_ioctl(fd, cmd, (unsigned long) sioc); + + if (!err) { + if (copy_in_user(&sioc32->length, &sioc->length, + sizeof(int))) + err = -EFAULT; + } + return err; +} + +static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) +{ + int i; + unsigned int cmd = 0; + + switch (cmd32) { + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: + return do_atmif_sioc(fd, cmd32, arg); + } + + for (i = 0; i < NR_ATM_IOCTL; i++) { + if (cmd32 == atm_ioctl_map[i].cmd32) { + cmd = atm_ioctl_map[i].cmd; + break; + } + } + if (i == NR_ATM_IOCTL) + return -EINVAL; + + switch (cmd) { + case ATM_GETNAMES: + return do_atm_iobuf(fd, cmd, arg); + + case ATM_GETLINKRATE: + case ATM_GETTYPE: + case ATM_GETESI: + case ATM_GETADDR: + case ATM_RSTADDR: + case ATM_ADDADDR: + case ATM_DELADDR: + case ATM_GETCIRANGE: + case ATM_SETCIRANGE: + case ATM_SETESI: + case ATM_SETESIF: + case ATM_GETSTAT: + case ATM_GETSTATZ: + case ATM_GETLOOP: + case ATM_SETLOOP: + case ATM_QUERYLOOP: + return do_atmif_sioc(fd, cmd, arg); + } + + return -EINVAL; +} + + +/* bridge */ +HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl) +HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl) +#ifdef CONFIG_NET +HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) +HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) +HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc) +HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc) + +HANDLE_IOCTL(SIOCDIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSARP, dev_ifsioc) +HANDLE_IOCTL(SIOCDARP, dev_ifsioc) + +HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) +HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) +HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) +HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) +HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) +HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) +HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) +HANDLE_IOCTL(SIOCADDRT, routing_ioctl) +HANDLE_IOCTL(SIOCDELRT, routing_ioctl) +HANDLE_IOCTL(SIOCBRADDIF, dev_ifsioc) +HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc) +/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ +HANDLE_IOCTL(SIOCRTMSG, ret_einval) +HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) +HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) +#endif +IGNORE_IOCTL(SIOCGIFCOUNT) +/* Little a */ +COMPATIBLE_IOCTL(ATMSIGD_CTRL) +COMPATIBLE_IOCTL(ATMARPD_CTRL) +COMPATIBLE_IOCTL(ATMLEC_CTRL) +COMPATIBLE_IOCTL(ATMLEC_MCAST) +COMPATIBLE_IOCTL(ATMLEC_DATA) +COMPATIBLE_IOCTL(ATM_SETSC) +COMPATIBLE_IOCTL(SIOCSIFATMTCP) +COMPATIBLE_IOCTL(SIOCMKCLIP) +COMPATIBLE_IOCTL(ATMARP_MKIP) +COMPATIBLE_IOCTL(ATMARP_SETENTRY) +COMPATIBLE_IOCTL(ATMARP_ENCAP) +COMPATIBLE_IOCTL(ATMTCP_CREATE) +COMPATIBLE_IOCTL(ATMTCP_REMOVE) +COMPATIBLE_IOCTL(ATMMPC_CTRL) +COMPATIBLE_IOCTL(ATMMPC_DATA) +HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) +HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) +COMPATIBLE_IOCTL(FIOSETOWN) +COMPATIBLE_IOCTL(SIOCSPGRP) +COMPATIBLE_IOCTL(FIOGETOWN) +COMPATIBLE_IOCTL(SIOCGPGRP) +COMPATIBLE_IOCTL(SIOCATMARK) +COMPATIBLE_IOCTL(SIOCSIFLINK) +COMPATIBLE_IOCTL(SIOCSIFNAME) +COMPATIBLE_IOCTL(SIOCSARP) +COMPATIBLE_IOCTL(SIOCGARP) +COMPATIBLE_IOCTL(SIOCDARP) +COMPATIBLE_IOCTL(SIOCSRARP) +COMPATIBLE_IOCTL(SIOCGRARP) +COMPATIBLE_IOCTL(SIOCDRARP) +COMPATIBLE_IOCTL(SIOCADDDLCI) +COMPATIBLE_IOCTL(SIOCDELDLCI) +COMPATIBLE_IOCTL(SIOCGMIIPHY) +COMPATIBLE_IOCTL(SIOCGMIIREG) +COMPATIBLE_IOCTL(SIOCSMIIREG) +COMPATIBLE_IOCTL(SIOCGIFVLAN) +COMPATIBLE_IOCTL(SIOCSIFVLAN) +COMPATIBLE_IOCTL(SIOCBRADDBR) +COMPATIBLE_IOCTL(SIOCBRDELBR) +#endif + static long compat_sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { -- cgit v1.2.3 From 206602217747382488fcae68351673cc9103debc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Nov 2009 08:09:06 +0000 Subject: appletalk: handle SIOCATALKDIFADDR compat ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We must not have a compat ioctl handler for SIOCATALKDIFADDR in common code, because the same number is used in other protocols with different data structures. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- fs/compat_ioctl.c | 1 - net/appletalk/ddp.c | 12 +++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index f4a5a01fc66..50d2a5fdc94 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -2536,7 +2536,6 @@ HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc) HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc) /* ioctls used by appletalk ddp.c */ -HANDLE_IOCTL(SIOCATALKDIFADDR, dev_ifsioc) HANDLE_IOCTL(SIOCDIFADDR, dev_ifsioc) HANDLE_IOCTL(SIOCSARP, dev_ifsioc) HANDLE_IOCTL(SIOCDARP, dev_ifsioc) diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 4b0ce2e2b46..7cd08b45c52 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1811,12 +1811,14 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { /* - * All Appletalk ioctls except SIOCATALKDIFADDR are standard. And - * SIOCATALKDIFADDR is handled by upper layer as well, so there is - * nothing to do. Eventually SIOCATALKDIFADDR should be moved - * here so there is no generic SIOCPROTOPRIVATE translation in the - * system. + * SIOCATALKDIFADDR is a SIOCPROTOPRIVATE ioctl number, so we + * cannot handle it in common code. The data we access if ifreq + * here is compatible, so we can simply call the native + * handler. */ + if (cmd == SIOCATALKDIFADDR) + return atalk_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); + return -ENOIOCTLCMD; } #endif -- cgit v1.2.3 From 6b96018b28bd93274b4b2a4c633a5d373fda0441 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Nov 2009 23:10:54 -0800 Subject: compat: move sockios handling to net/socket.c This removes the original socket compat_ioctl code from fs/compat_ioctl.c and converts the code from the copy in net/socket.c into a single function. We add a few cycles of runtime to compat_sock_ioctl() with the long switch() statement, but gain some cycles in return by simplifying the call chain to get there. Due to better inlining, save 1.5kb of object size in the process, and enable further savings: before: text data bss dec hex filename 13540 18008 2080 33628 835c obj/fs/compat_ioctl.o 14565 636 40 15241 3b89 obj/net/socket.o after: text data bss dec hex filename 8916 15176 2080 26172 663c obj/fs/compat_ioctl.o 20725 636 40 21401 5399 obj/net/socket.o Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- fs/compat_ioctl.c | 722 ------------------------------------------------------ net/socket.c | 468 ++++++++++++++++++----------------- 2 files changed, 240 insertions(+), 950 deletions(-) (limited to 'net') diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 50d2a5fdc94..cacf8a83e39 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -246,422 +246,6 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd, unsigned return err; } -#ifdef CONFIG_NET -static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct compat_timeval __user *up = compat_ptr(arg); - struct timeval ktv; - mm_segment_t old_fs = get_fs(); - int err; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&ktv); - set_fs(old_fs); - if(!err) { - err = put_user(ktv.tv_sec, &up->tv_sec); - err |= __put_user(ktv.tv_usec, &up->tv_usec); - } - return err; -} - -static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct compat_timespec __user *up = compat_ptr(arg); - struct timespec kts; - mm_segment_t old_fs = get_fs(); - int err; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&kts); - set_fs(old_fs); - if (!err) { - err = put_user(kts.tv_sec, &up->tv_sec); - err |= __put_user(kts.tv_nsec, &up->tv_nsec); - } - return err; -} - -struct ifmap32 { - compat_ulong_t mem_start; - compat_ulong_t mem_end; - unsigned short base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct ifreq32 { -#define IFHWADDRLEN 6 -#define IFNAMSIZ 16 - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - compat_int_t ifru_ivalue; - compat_int_t ifru_mtu; - struct ifmap32 ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - char ifru_newname[IFNAMSIZ]; - compat_caddr_t ifru_data; - /* XXXX? ifru_settings should be here */ - } ifr_ifru; -}; - -struct ifconf32 { - compat_int_t ifc_len; /* size of buffer */ - compat_caddr_t ifcbuf; -}; - -static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq __user *uifr; - int err; - - uifr = compat_alloc_user_space(sizeof(struct ifreq)); - if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32))) - return -EFAULT; - - err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr); - if (err) - return err; - - if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32))) - return -EFAULT; - - return 0; -} - -static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifconf32 ifc32; - struct ifconf ifc; - struct ifconf __user *uifc; - struct ifreq32 __user *ifr32; - struct ifreq __user *ifr; - unsigned int i, j; - int err; - - if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32))) - return -EFAULT; - - if (ifc32.ifcbuf == 0) { - ifc32.ifc_len = 0; - ifc.ifc_len = 0; - ifc.ifc_req = NULL; - uifc = compat_alloc_user_space(sizeof(struct ifconf)); - } else { - size_t len =((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * - sizeof (struct ifreq); - uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); - ifc.ifc_len = len; - ifr = ifc.ifc_req = (void __user *)(uifc + 1); - ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { - if (copy_in_user(ifr, ifr32, sizeof(struct ifreq32))) - return -EFAULT; - ifr++; - ifr32++; - } - } - if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) - return -EFAULT; - - err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)uifc); - if (err) - return err; - - if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) - return -EFAULT; - - ifr = ifc.ifc_req; - ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0, j = 0; - i + sizeof (struct ifreq32) <= ifc32.ifc_len && j < ifc.ifc_len; - i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { - if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) - return -EFAULT; - ifr32++; - ifr++; - } - - if (ifc32.ifcbuf == 0) { - /* Translate from 64-bit structure multiple to - * a 32-bit one. - */ - i = ifc.ifc_len; - i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); - ifc32.ifc_len = i; - } else { - ifc32.ifc_len = i; - } - if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) - return -EFAULT; - - return 0; -} - -static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq __user *ifr; - struct ifreq32 __user *ifr32; - u32 data; - void __user *datap; - - ifr = compat_alloc_user_space(sizeof(*ifr)); - ifr32 = compat_ptr(arg); - - if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) - return -EFAULT; - - if (get_user(data, &ifr32->ifr_ifru.ifru_data)) - return -EFAULT; - - datap = compat_ptr(data); - if (put_user(datap, &ifr->ifr_ifru.ifru_data)) - return -EFAULT; - - return sys_ioctl(fd, cmd, (unsigned long) ifr); -} - -static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq kifr; - struct ifreq __user *uifr; - struct ifreq32 __user *ifr32 = compat_ptr(arg); - mm_segment_t old_fs; - int err; - u32 data; - void __user *datap; - - switch (cmd) { - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - if (copy_from_user(&kifr, ifr32, sizeof(struct ifreq32))) - return -EFAULT; - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&kifr); - set_fs (old_fs); - - return err; - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: - uifr = compat_alloc_user_space(sizeof(*uifr)); - if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) - return -EFAULT; - - if (get_user(data, &ifr32->ifr_ifru.ifru_data)) - return -EFAULT; - - datap = compat_ptr(data); - if (put_user(datap, &uifr->ifr_ifru.ifru_data)) - return -EFAULT; - - return sys_ioctl (fd, cmd, (unsigned long)uifr); - default: - return -EINVAL; - }; -} - -static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq __user *u_ifreq64; - struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); - char tmp_buf[IFNAMSIZ]; - void __user *data64; - u32 data32; - - if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), - IFNAMSIZ)) - return -EFAULT; - if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) - return -EFAULT; - data64 = compat_ptr(data32); - - u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); - - /* Don't check these user accesses, just let that get trapped - * in the ioctl handler instead. - */ - if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], - IFNAMSIZ)) - return -EFAULT; - if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) - return -EFAULT; - - return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); -} - -static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq ifr; - struct ifreq32 __user *uifr32; - struct ifmap32 __user *uifmap32; - mm_segment_t old_fs; - int err; - - uifr32 = compat_ptr(arg); - uifmap32 = &uifr32->ifr_ifru.ifru_map; - switch (cmd) { - case SIOCSIFMAP: - err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); - err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); - err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); - err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); - err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq); - err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma); - err |= __get_user(ifr.ifr_map.port, &uifmap32->port); - if (err) - return -EFAULT; - break; - case SIOCSHWTSTAMP: - if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) - return -EFAULT; - ifr.ifr_data = compat_ptr(uifr32->ifr_ifru.ifru_data); - break; - default: - if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) - return -EFAULT; - break; - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); - set_fs (old_fs); - if (!err) { - switch (cmd) { - case SIOCGIFFLAGS: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFMEM: - case SIOCGIFHWADDR: - case SIOCGIFINDEX: - case SIOCGIFADDR: - case SIOCGIFBRDADDR: - case SIOCGIFDSTADDR: - case SIOCGIFNETMASK: - case SIOCGIFTXQLEN: - if (copy_to_user(uifr32, &ifr, sizeof(*uifr32))) - return -EFAULT; - break; - case SIOCGIFMAP: - err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); - err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); - err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); - err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); - err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq); - err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma); - err |= __put_user(ifr.ifr_map.port, &uifmap32->port); - if (err) - err = -EFAULT; - break; - } - } - return err; -} - -struct rtentry32 { - u32 rt_pad1; - struct sockaddr rt_dst; /* target address */ - struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ - struct sockaddr rt_genmask; /* target network mask (IP) */ - unsigned short rt_flags; - short rt_pad2; - u32 rt_pad3; - unsigned char rt_tos; - unsigned char rt_class; - short rt_pad4; - short rt_metric; /* +1 for binary compatibility! */ - /* char * */ u32 rt_dev; /* forcing the device at add */ - u32 rt_mtu; /* per route MTU/Window */ - u32 rt_window; /* Window clamping */ - unsigned short rt_irtt; /* Initial RTT */ - -}; - -struct in6_rtmsg32 { - struct in6_addr rtmsg_dst; - struct in6_addr rtmsg_src; - struct in6_addr rtmsg_gateway; - u32 rtmsg_type; - u16 rtmsg_dst_len; - u16 rtmsg_src_len; - u32 rtmsg_metric; - u32 rtmsg_info; - u32 rtmsg_flags; - s32 rtmsg_ifindex; -}; - -static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - int ret; - void *r = NULL; - struct in6_rtmsg r6; - struct rtentry r4; - char devname[16]; - u32 rtdev; - mm_segment_t old_fs = get_fs(); - - struct socket *mysock = sockfd_lookup(fd, &ret); - - if (mysock && mysock->sk && mysock->sk->sk_family == AF_INET6) { /* ipv6 */ - struct in6_rtmsg32 __user *ur6 = compat_ptr(arg); - ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst), - 3 * sizeof(struct in6_addr)); - ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type)); - ret |= __get_user (r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); - ret |= __get_user (r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); - ret |= __get_user (r6.rtmsg_metric, &(ur6->rtmsg_metric)); - ret |= __get_user (r6.rtmsg_info, &(ur6->rtmsg_info)); - ret |= __get_user (r6.rtmsg_flags, &(ur6->rtmsg_flags)); - ret |= __get_user (r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); - - r = (void *) &r6; - } else { /* ipv4 */ - struct rtentry32 __user *ur4 = compat_ptr(arg); - ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst), - 3 * sizeof(struct sockaddr)); - ret |= __get_user (r4.rt_flags, &(ur4->rt_flags)); - ret |= __get_user (r4.rt_metric, &(ur4->rt_metric)); - ret |= __get_user (r4.rt_mtu, &(ur4->rt_mtu)); - ret |= __get_user (r4.rt_window, &(ur4->rt_window)); - ret |= __get_user (r4.rt_irtt, &(ur4->rt_irtt)); - ret |= __get_user (rtdev, &(ur4->rt_dev)); - if (rtdev) { - ret |= copy_from_user (devname, compat_ptr(rtdev), 15); - r4.rt_dev = devname; devname[15] = 0; - } else - r4.rt_dev = NULL; - - r = (void *) &r4; - } - - if (ret) { - ret = -EFAULT; - goto out; - } - - set_fs (KERNEL_DS); - ret = sys_ioctl (fd, cmd, (unsigned long) r); - set_fs (old_fs); - -out: - if (mysock) - sockfd_put(mysock); - - return ret; -} -#endif - #ifdef CONFIG_BLOCK typedef struct sg_io_hdr32 { compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ @@ -1206,170 +790,6 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long a return err; } -struct atmif_sioc32 { - compat_int_t number; - compat_int_t length; - compat_caddr_t arg; -}; - -struct atm_iobuf32 { - compat_int_t length; - compat_caddr_t buffer; -}; - -#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) -#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) -#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) -#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) -#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) -#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) -#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) -#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) -#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) -#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) -#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) -#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) -#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) -#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) -#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) -#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) -#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} atm_ioctl_map[] = { - { ATM_GETLINKRATE32, ATM_GETLINKRATE }, - { ATM_GETNAMES32, ATM_GETNAMES }, - { ATM_GETTYPE32, ATM_GETTYPE }, - { ATM_GETESI32, ATM_GETESI }, - { ATM_GETADDR32, ATM_GETADDR }, - { ATM_RSTADDR32, ATM_RSTADDR }, - { ATM_ADDADDR32, ATM_ADDADDR }, - { ATM_DELADDR32, ATM_DELADDR }, - { ATM_GETCIRANGE32, ATM_GETCIRANGE }, - { ATM_SETCIRANGE32, ATM_SETCIRANGE }, - { ATM_SETESI32, ATM_SETESI }, - { ATM_SETESIF32, ATM_SETESIF }, - { ATM_GETSTAT32, ATM_GETSTAT }, - { ATM_GETSTATZ32, ATM_GETSTATZ }, - { ATM_GETLOOP32, ATM_GETLOOP }, - { ATM_SETLOOP32, ATM_SETLOOP }, - { ATM_QUERYLOOP32, ATM_QUERYLOOP } -}; - -#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map) - -static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct atm_iobuf __user *iobuf; - struct atm_iobuf32 __user *iobuf32; - u32 data; - void __user *datap; - int len, err; - - iobuf = compat_alloc_user_space(sizeof(*iobuf)); - iobuf32 = compat_ptr(arg); - - if (get_user(len, &iobuf32->length) || - get_user(data, &iobuf32->buffer)) - return -EFAULT; - datap = compat_ptr(data); - if (put_user(len, &iobuf->length) || - put_user(datap, &iobuf->buffer)) - return -EFAULT; - - err = sys_ioctl(fd, cmd, (unsigned long)iobuf); - - if (!err) { - if (copy_in_user(&iobuf32->length, &iobuf->length, - sizeof(int))) - err = -EFAULT; - } - - return err; -} - -static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct atmif_sioc __user *sioc; - struct atmif_sioc32 __user *sioc32; - u32 data; - void __user *datap; - int err; - - sioc = compat_alloc_user_space(sizeof(*sioc)); - sioc32 = compat_ptr(arg); - - if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) || - get_user(data, &sioc32->arg)) - return -EFAULT; - datap = compat_ptr(data); - if (put_user(datap, &sioc->arg)) - return -EFAULT; - - err = sys_ioctl(fd, cmd, (unsigned long) sioc); - - if (!err) { - if (copy_in_user(&sioc32->length, &sioc->length, - sizeof(int))) - err = -EFAULT; - } - return err; -} - -static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) -{ - int i; - unsigned int cmd = 0; - - switch (cmd32) { - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_GETDIAG: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: - return do_atmif_sioc(fd, cmd32, arg); - } - - for (i = 0; i < NR_ATM_IOCTL; i++) { - if (cmd32 == atm_ioctl_map[i].cmd32) { - cmd = atm_ioctl_map[i].cmd; - break; - } - } - if (i == NR_ATM_IOCTL) - return -EINVAL; - - switch (cmd) { - case ATM_GETNAMES: - return do_atm_iobuf(fd, cmd, arg); - - case ATM_GETLINKRATE: - case ATM_GETTYPE: - case ATM_GETESI: - case ATM_GETADDR: - case ATM_RSTADDR: - case ATM_ADDADDR: - case ATM_DELADDR: - case ATM_GETCIRANGE: - case ATM_SETCIRANGE: - case ATM_SETESI: - case ATM_SETESIF: - case ATM_GETSTAT: - case ATM_GETSTATZ: - case ATM_GETLOOP: - case ATM_SETLOOP: - case ATM_QUERYLOOP: - return do_atmif_sioc(fd, cmd, arg); - } - - return -EINVAL; -} - static __used int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) { @@ -1712,21 +1132,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a return sys_ioctl(fd, cmd, (unsigned long)tdata); } -/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE - * for some operations; this forces use of the newer bridge-utils that - * use compatible ioctls - */ -static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - u32 tmp; - - if (get_user(tmp, (u32 __user *) arg)) - return -EFAULT; - if (tmp == BRCTL_GET_VERSION) - return BRCTL_VERSION + 1; - return -EINVAL; -} - #define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t) #define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t) #define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t) @@ -2014,28 +1419,6 @@ COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ COMPATIBLE_IOCTL(MTIOCTOP) /* Socket level stuff */ COMPATIBLE_IOCTL(FIOQSIZE) -COMPATIBLE_IOCTL(FIOSETOWN) -COMPATIBLE_IOCTL(SIOCSPGRP) -COMPATIBLE_IOCTL(FIOGETOWN) -COMPATIBLE_IOCTL(SIOCGPGRP) -COMPATIBLE_IOCTL(SIOCATMARK) -COMPATIBLE_IOCTL(SIOCSIFLINK) -COMPATIBLE_IOCTL(SIOCSIFNAME) -COMPATIBLE_IOCTL(SIOCSARP) -COMPATIBLE_IOCTL(SIOCGARP) -COMPATIBLE_IOCTL(SIOCDARP) -COMPATIBLE_IOCTL(SIOCSRARP) -COMPATIBLE_IOCTL(SIOCGRARP) -COMPATIBLE_IOCTL(SIOCDRARP) -COMPATIBLE_IOCTL(SIOCADDDLCI) -COMPATIBLE_IOCTL(SIOCDELDLCI) -COMPATIBLE_IOCTL(SIOCGMIIPHY) -COMPATIBLE_IOCTL(SIOCGMIIREG) -COMPATIBLE_IOCTL(SIOCSMIIREG) -COMPATIBLE_IOCTL(SIOCGIFVLAN) -COMPATIBLE_IOCTL(SIOCSIFVLAN) -COMPATIBLE_IOCTL(SIOCBRADDBR) -COMPATIBLE_IOCTL(SIOCBRDELBR) #ifdef CONFIG_BLOCK /* SG stuff */ COMPATIBLE_IOCTL(SG_SET_TIMEOUT) @@ -2291,22 +1674,6 @@ COMPATIBLE_IOCTL(RAW_SETBIND) COMPATIBLE_IOCTL(RAW_GETBIND) /* SMB ioctls which do not need any translations */ COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) -/* Little a */ -COMPATIBLE_IOCTL(ATMSIGD_CTRL) -COMPATIBLE_IOCTL(ATMARPD_CTRL) -COMPATIBLE_IOCTL(ATMLEC_CTRL) -COMPATIBLE_IOCTL(ATMLEC_MCAST) -COMPATIBLE_IOCTL(ATMLEC_DATA) -COMPATIBLE_IOCTL(ATM_SETSC) -COMPATIBLE_IOCTL(SIOCSIFATMTCP) -COMPATIBLE_IOCTL(SIOCMKCLIP) -COMPATIBLE_IOCTL(ATMARP_MKIP) -COMPATIBLE_IOCTL(ATMARP_SETENTRY) -COMPATIBLE_IOCTL(ATMARP_ENCAP) -COMPATIBLE_IOCTL(ATMTCP_CREATE) -COMPATIBLE_IOCTL(ATMTCP_REMOVE) -COMPATIBLE_IOCTL(ATMMPC_CTRL) -COMPATIBLE_IOCTL(ATMMPC_DATA) /* Watchdog */ COMPATIBLE_IOCTL(WDIOC_GETSUPPORT) COMPATIBLE_IOCTL(WDIOC_GETSTATUS) @@ -2512,60 +1879,6 @@ COMPATIBLE_IOCTL(JSIOCGBUTTONS) COMPATIBLE_IOCTL(JSIOCGNAME(0)) /* now things that need handlers */ -#ifdef CONFIG_NET -HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) -HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) -HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc) -HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc) - -/* ioctls used by appletalk ddp.c */ -HANDLE_IOCTL(SIOCDIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSARP, dev_ifsioc) -HANDLE_IOCTL(SIOCDARP, dev_ifsioc) - -HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) -HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) -HANDLE_IOCTL(SIOCADDRT, routing_ioctl) -HANDLE_IOCTL(SIOCDELRT, routing_ioctl) -HANDLE_IOCTL(SIOCBRADDIF, dev_ifsioc) -HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc) -/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ -HANDLE_IOCTL(SIOCRTMSG, ret_einval) -HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) -HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) -#endif #ifdef CONFIG_BLOCK HANDLE_IOCTL(SG_IO,sg_ioctl_trans) HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans) @@ -2590,31 +1903,6 @@ HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) /* One SMB ioctl needs translations. */ #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) -HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) /* block stuff */ #ifdef CONFIG_BLOCK /* loop */ @@ -2649,11 +1937,7 @@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32) HANDLE_IOCTL(I2C_FUNCS, w_long) HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl) HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl) -/* bridge */ -HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl) -HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl) /* Not implemented in the native kernel */ -IGNORE_IOCTL(SIOCGIFCOUNT) HANDLE_IOCTL(RTC_IRQP_READ32, rtc_ioctl) HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl) HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl) @@ -2808,12 +2092,6 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, goto found_handler; } -#ifdef CONFIG_NET - if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) && - cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { - error = siocdevprivate_ioctl(fd, cmd, arg); - } else -#endif { static int count; diff --git a/net/socket.c b/net/socket.c index 344bd230b83..901d709a7be 100644 --- a/net/socket.c +++ b/net/socket.c @@ -97,6 +97,20 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + static int sock_no_open(struct inode *irrelevant, struct file *dontcare); static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); @@ -919,6 +933,24 @@ void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) EXPORT_SYMBOL(dlci_ioctl_set); +static long sock_do_ioctl(struct net *net, struct socket *sock, + unsigned int cmd, unsigned long arg) +{ + int err; + void __user *argp = (void __user *)arg; + + err = sock->ops->ioctl(sock, cmd, arg); + + /* + * If this ioctl is unknown try to hand it down + * to the NIC driver. + */ + if (err == -ENOIOCTLCMD) + err = dev_ioctl(net, cmd, argp); + + return err; +} + /* * With an ioctl, arg may well be a user mode pointer, but we don't know * what to do with it - that's up to the protocol still. @@ -992,14 +1024,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&dlci_ioctl_mutex); break; default: - err = sock->ops->ioctl(sock, cmd, arg); - - /* - * If this ioctl is unknown try to hand it down - * to the NIC driver. - */ - if (err == -ENOIOCTLCMD) - err = dev_ioctl(net, cmd, argp); + err = sock_do_ioctl(net, sock, cmd, arg); break; } return err; @@ -2459,16 +2484,15 @@ void socket_seq_show(struct seq_file *seq) #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_COMPAT -#if 0 -static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) +static int do_siocgstamp(struct net *net, struct socket *sock, + unsigned int cmd, struct compat_timeval __user *up) { - struct compat_timeval __user *up = compat_ptr(arg); mm_segment_t old_fs = get_fs(); struct timeval ktv; int err; set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&ktv); + err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); set_fs(old_fs); if (!err) { err = put_user(ktv.tv_sec, &up->tv_sec); @@ -2477,15 +2501,15 @@ static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) return err; } -static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg) +static int do_siocgstampns(struct net *net, struct socket *sock, + unsigned int cmd, struct compat_timespec __user *up) { - struct compat_timespec __user *up = compat_ptr(arg); mm_segment_t old_fs = get_fs(); struct timespec kts; int err; set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&kts); + err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); set_fs(old_fs); if (!err) { err = put_user(kts.tv_sec, &up->tv_sec); @@ -2494,73 +2518,36 @@ static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg) return err; } -struct ifmap32 { - compat_ulong_t mem_start; - compat_ulong_t mem_end; - unsigned short base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct ifreq32 { -#define IFHWADDRLEN 6 -#define IFNAMSIZ 16 - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - compat_int_t ifru_ivalue; - compat_int_t ifru_mtu; - struct ifmap32 ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - char ifru_newname[IFNAMSIZ]; - compat_caddr_t ifru_data; - /* XXXX? ifru_settings should be here */ - } ifr_ifru; -}; - -struct ifconf32 { - compat_int_t ifc_len; /* size of buffer */ - compat_caddr_t ifcbuf; -}; - -static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) +static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32) { struct ifreq __user *uifr; int err; uifr = compat_alloc_user_space(sizeof(struct ifreq)); - if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32))) + if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) return -EFAULT; - err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr); + err = dev_ioctl(net, SIOCGIFNAME, uifr); if (err) return err; - if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32))) + if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq))) return -EFAULT; return 0; } -static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) +static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) { - struct ifconf32 ifc32; + struct compat_ifconf ifc32; struct ifconf ifc; struct ifconf __user *uifc; - struct ifreq32 __user *ifr32; + struct compat_ifreq __user *ifr32; struct ifreq __user *ifr; unsigned int i, j; int err; - if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32))) + if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) return -EFAULT; if (ifc32.ifcbuf == 0) { @@ -2569,14 +2556,14 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) ifc.ifc_req = NULL; uifc = compat_alloc_user_space(sizeof(struct ifconf)); } else { - size_t len =((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * + size_t len =((ifc32.ifc_len / sizeof (struct compat_ifreq)) + 1) * sizeof (struct ifreq); uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); ifc.ifc_len = len; ifr = ifc.ifc_req = (void __user *)(uifc + 1); ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { - if (copy_in_user(ifr, ifr32, sizeof(struct ifreq32))) + for (i = 0; i < ifc32.ifc_len; i += sizeof (struct compat_ifreq)) { + if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq))) return -EFAULT; ifr++; ifr32++; @@ -2585,7 +2572,7 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) return -EFAULT; - err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)uifc); + err = dev_ioctl(net, SIOCGIFCONF, uifc); if (err) return err; @@ -2595,9 +2582,9 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) ifr = ifc.ifc_req; ifr32 = compat_ptr(ifc32.ifcbuf); for (i = 0, j = 0; - i + sizeof (struct ifreq32) <= ifc32.ifc_len && j < ifc.ifc_len; - i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { - if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) + i + sizeof (struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len; + i += sizeof (struct compat_ifreq), j += sizeof (struct ifreq)) { + if (copy_in_user(ifr32, ifr, sizeof (struct compat_ifreq))) return -EFAULT; ifr32++; ifr++; @@ -2608,26 +2595,24 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) * a 32-bit one. */ i = ifc.ifc_len; - i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); + i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq)); ifc32.ifc_len = i; } else { ifc32.ifc_len = i; } - if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) + if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) return -EFAULT; return 0; } -static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) { struct ifreq __user *ifr; - struct ifreq32 __user *ifr32; u32 data; void __user *datap; ifr = compat_alloc_user_space(sizeof(*ifr)); - ifr32 = compat_ptr(arg); if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) return -EFAULT; @@ -2639,14 +2624,14 @@ static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) if (put_user(datap, &ifr->ifr_ifru.ifru_data)) return -EFAULT; - return sys_ioctl(fd, cmd, (unsigned long) ifr); + return dev_ioctl(net, SIOCETHTOOL, ifr); } -static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static int bond_ioctl(struct net *net, unsigned int cmd, + struct compat_ifreq __user *ifr32) { struct ifreq kifr; struct ifreq __user *uifr; - struct ifreq32 __user *ifr32 = compat_ptr(arg); mm_segment_t old_fs; int err; u32 data; @@ -2657,12 +2642,12 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: case SIOCBONDCHANGEACTIVE: - if (copy_from_user(&kifr, ifr32, sizeof(struct ifreq32))) + if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq))) return -EFAULT; old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&kifr); + err = dev_ioctl(net, cmd, &kifr); set_fs (old_fs); return err; @@ -2679,16 +2664,16 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) if (put_user(datap, &uifr->ifr_ifru.ifru_data)) return -EFAULT; - return sys_ioctl (fd, cmd, (unsigned long)uifr); + return dev_ioctl(net, cmd, uifr); default: return -EINVAL; }; } -static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, + struct compat_ifreq __user *u_ifreq32) { struct ifreq __user *u_ifreq64; - struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); char tmp_buf[IFNAMSIZ]; void __user *data64; u32 data32; @@ -2711,18 +2696,17 @@ static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) return -EFAULT; - return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); + return dev_ioctl(net, cmd, u_ifreq64); } -static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) +static int dev_ifsioc(struct net *net, struct socket *sock, + unsigned int cmd, struct compat_ifreq __user *uifr32) { struct ifreq ifr; - struct ifreq32 __user *uifr32; - struct ifmap32 __user *uifmap32; + struct compat_ifmap __user *uifmap32; mm_segment_t old_fs; int err; - uifr32 = compat_ptr(arg); uifmap32 = &uifr32->ifr_ifru.ifru_map; switch (cmd) { case SIOCSIFMAP: @@ -2748,7 +2732,7 @@ static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) } old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ifr); set_fs (old_fs); if (!err) { switch (cmd) { @@ -2813,7 +2797,8 @@ struct in6_rtmsg32 { s32 rtmsg_ifindex; }; -static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static int routing_ioctl(struct net *net, struct socket *sock, + unsigned int cmd, void __user *argp) { int ret; void *r = NULL; @@ -2823,10 +2808,8 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) u32 rtdev; mm_segment_t old_fs = get_fs(); - struct socket *mysock = sockfd_lookup(fd, &ret); - - if (mysock && mysock->sk && mysock->sk->sk_family == AF_INET6) { /* ipv6 */ - struct in6_rtmsg32 __user *ur6 = compat_ptr(arg); + if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */ + struct in6_rtmsg32 __user *ur6 = argp; ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst), 3 * sizeof(struct in6_addr)); ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type)); @@ -2839,7 +2822,7 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) r = (void *) &r6; } else { /* ipv4 */ - struct rtentry32 __user *ur4 = compat_ptr(arg); + struct rtentry32 __user *ur4 = argp; ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst), 3 * sizeof(struct sockaddr)); ret |= __get_user (r4.rt_flags, &(ur4->rt_flags)); @@ -2863,13 +2846,10 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) } set_fs (KERNEL_DS); - ret = sys_ioctl (fd, cmd, (unsigned long) r); + ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); set_fs (old_fs); out: - if (mysock) - sockfd_put(mysock); - return ret; } @@ -2877,11 +2857,11 @@ out: * for some operations; this forces use of the newer bridge-utils that * use compatiable ioctls */ -static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static int old_bridge_ioctl(compat_ulong_t __user *argp) { - u32 tmp; + compat_ulong_t tmp; - if (get_user(tmp, (u32 __user *) arg)) + if (get_user(tmp, argp)) return -EFAULT; if (tmp == BRCTL_GET_VERSION) return BRCTL_VERSION + 1; @@ -2942,7 +2922,8 @@ static struct { #define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map) -static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) +static int do_atm_iobuf(struct net *net, struct socket *sock, + unsigned int cmd, unsigned long arg) { struct atm_iobuf __user *iobuf; struct atm_iobuf32 __user *iobuf32; @@ -2961,7 +2942,7 @@ static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) put_user(datap, &iobuf->buffer)) return -EFAULT; - err = sys_ioctl(fd, cmd, (unsigned long)iobuf); + err = sock_do_ioctl(net, sock, cmd, (unsigned long)iobuf); if (!err) { if (copy_in_user(&iobuf32->length, &iobuf->length, @@ -2972,7 +2953,8 @@ static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) return err; } -static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) +static int do_atmif_sioc(struct net *net, struct socket *sock, + unsigned int cmd, unsigned long arg) { struct atmif_sioc __user *sioc; struct atmif_sioc32 __user *sioc32; @@ -2990,7 +2972,7 @@ static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) if (put_user(datap, &sioc->arg)) return -EFAULT; - err = sys_ioctl(fd, cmd, (unsigned long) sioc); + err = sock_do_ioctl(net, sock, cmd, (unsigned long) sioc); if (!err) { if (copy_in_user(&sioc32->length, &sioc->length, @@ -3000,7 +2982,8 @@ static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) return err; } -static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) +static int do_atm_ioctl(struct net *net, struct socket *sock, + unsigned int cmd32, unsigned long arg) { int i; unsigned int cmd = 0; @@ -3014,7 +2997,7 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) case SONET_SETFRAMING: case SONET_GETFRAMING: case SONET_GETFRSENSE: - return do_atmif_sioc(fd, cmd32, arg); + return do_atmif_sioc(net, sock, cmd32, arg); } for (i = 0; i < NR_ATM_IOCTL; i++) { @@ -3028,7 +3011,7 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) switch (cmd) { case ATM_GETNAMES: - return do_atm_iobuf(fd, cmd, arg); + return do_atm_iobuf(net, sock, cmd, arg); case ATM_GETLINKRATE: case ATM_GETTYPE: @@ -3046,134 +3029,160 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) case ATM_GETLOOP: case ATM_SETLOOP: case ATM_QUERYLOOP: - return do_atmif_sioc(fd, cmd, arg); + return do_atmif_sioc(net, sock, cmd, arg); } return -EINVAL; } +static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = compat_ptr(arg); + struct sock *sk = sock->sk; + struct net *net = sock_net(sk); -/* bridge */ -HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl) -HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl) -#ifdef CONFIG_NET -HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) -HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) -HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc) -HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc) - -HANDLE_IOCTL(SIOCDIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSARP, dev_ifsioc) -HANDLE_IOCTL(SIOCDARP, dev_ifsioc) - -HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) -HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) -HANDLE_IOCTL(SIOCADDRT, routing_ioctl) -HANDLE_IOCTL(SIOCDELRT, routing_ioctl) -HANDLE_IOCTL(SIOCBRADDIF, dev_ifsioc) -HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc) -/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ -HANDLE_IOCTL(SIOCRTMSG, ret_einval) -HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) -HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns) -#endif -IGNORE_IOCTL(SIOCGIFCOUNT) -/* Little a */ -COMPATIBLE_IOCTL(ATMSIGD_CTRL) -COMPATIBLE_IOCTL(ATMARPD_CTRL) -COMPATIBLE_IOCTL(ATMLEC_CTRL) -COMPATIBLE_IOCTL(ATMLEC_MCAST) -COMPATIBLE_IOCTL(ATMLEC_DATA) -COMPATIBLE_IOCTL(ATM_SETSC) -COMPATIBLE_IOCTL(SIOCSIFATMTCP) -COMPATIBLE_IOCTL(SIOCMKCLIP) -COMPATIBLE_IOCTL(ATMARP_MKIP) -COMPATIBLE_IOCTL(ATMARP_SETENTRY) -COMPATIBLE_IOCTL(ATMARP_ENCAP) -COMPATIBLE_IOCTL(ATMTCP_CREATE) -COMPATIBLE_IOCTL(ATMTCP_REMOVE) -COMPATIBLE_IOCTL(ATMMPC_CTRL) -COMPATIBLE_IOCTL(ATMMPC_DATA) -HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) -COMPATIBLE_IOCTL(FIOSETOWN) -COMPATIBLE_IOCTL(SIOCSPGRP) -COMPATIBLE_IOCTL(FIOGETOWN) -COMPATIBLE_IOCTL(SIOCGPGRP) -COMPATIBLE_IOCTL(SIOCATMARK) -COMPATIBLE_IOCTL(SIOCSIFLINK) -COMPATIBLE_IOCTL(SIOCSIFNAME) -COMPATIBLE_IOCTL(SIOCSARP) -COMPATIBLE_IOCTL(SIOCGARP) -COMPATIBLE_IOCTL(SIOCDARP) -COMPATIBLE_IOCTL(SIOCSRARP) -COMPATIBLE_IOCTL(SIOCGRARP) -COMPATIBLE_IOCTL(SIOCDRARP) -COMPATIBLE_IOCTL(SIOCADDDLCI) -COMPATIBLE_IOCTL(SIOCDELDLCI) -COMPATIBLE_IOCTL(SIOCGMIIPHY) -COMPATIBLE_IOCTL(SIOCGMIIREG) -COMPATIBLE_IOCTL(SIOCSMIIREG) -COMPATIBLE_IOCTL(SIOCGIFVLAN) -COMPATIBLE_IOCTL(SIOCSIFVLAN) -COMPATIBLE_IOCTL(SIOCBRADDBR) -COMPATIBLE_IOCTL(SIOCBRDELBR) -#endif + if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) + return siocdevprivate_ioctl(net, cmd, argp); + + switch (cmd) { + case SIOCSIFBR: + case SIOCGIFBR: + return old_bridge_ioctl(argp); + case SIOCGIFNAME: + return dev_ifname32(net, argp); + case SIOCGIFCONF: + return dev_ifconf(net, argp); + case SIOCETHTOOL: + return ethtool_ioctl(net, argp); + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDSLAVEINFOQUERY: + case SIOCBONDINFOQUERY: + case SIOCBONDCHANGEACTIVE: + return bond_ioctl(net, cmd, argp); + case SIOCADDRT: + case SIOCDELRT: + return routing_ioctl(net, sock, cmd, argp); + case SIOCGSTAMP: + return do_siocgstamp(net, sock, cmd, argp); + case SIOCGSTAMPNS: + return do_siocgstampns(net, sock, cmd, argp); +/* Note SIOCRTMSG is no longer, so this is safe and + * the user would have seen just an -EINVAL anyways. */ + case SIOCRTMSG: + case SIOCGIFCOUNT: + return -EINVAL; + + case FIOSETOWN: + case SIOCSPGRP: + case FIOGETOWN: + case SIOCGPGRP: + case SIOCBRADDBR: + case SIOCBRDELBR: + case SIOCGIFVLAN: + case SIOCSIFVLAN: + case SIOCADDDLCI: + case SIOCDELDLCI: + return sock_ioctl(file, cmd, arg); + + case SIOCGIFFLAGS: + case SIOCSIFFLAGS: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case SIOCADDMULTI: + case SIOCDELMULTI: + case SIOCGIFINDEX: + case SIOCGIFMAP: + case SIOCSIFMAP: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCSIFHWBROADCAST: + case SIOCSHWTSTAMP: + case SIOCDIFADDR: +/* case SIOCSARP: duplicate */ +/* case SIOCDARP: duplicate */ + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCSIFPFLAGS: + case SIOCGIFPFLAGS: + case SIOCGIFTXQLEN: + case SIOCSIFTXQLEN: + case SIOCBRADDIF: + case SIOCBRDELIF: + return dev_ifsioc(net, sock, cmd, argp); + case ATM_GETLINKRATE32: + case ATM_GETNAMES32: + case ATM_GETTYPE32: + case ATM_GETESI32: + case ATM_GETADDR32: + case ATM_RSTADDR32: + case ATM_ADDADDR32: + case ATM_DELADDR32: + case ATM_GETCIRANGE32: + case ATM_SETCIRANGE32: + case ATM_SETESI32: + case ATM_SETESIF32: + case ATM_GETSTAT32: + case ATM_GETSTATZ32: + case ATM_GETLOOP32: + case ATM_SETLOOP32: + case ATM_QUERYLOOP32: + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: + return do_atm_ioctl(net, sock, cmd, arg); + + case ATMSIGD_CTRL: + case ATMARPD_CTRL: + case ATMLEC_CTRL: + case ATMLEC_MCAST: + case ATMLEC_DATA: + case ATM_SETSC: + case SIOCSIFATMTCP: + case SIOCMKCLIP: + case ATMARP_MKIP: + case ATMARP_SETENTRY: + case ATMARP_ENCAP: + case ATMTCP_CREATE: + case ATMTCP_REMOVE: + case ATMMPC_CTRL: + case ATMMPC_DATA: + + case SIOCSARP: + case SIOCGARP: + case SIOCDARP: + + case SIOCATMARK: + case SIOCSIFLINK: + case SIOCSIFNAME: + case SIOCSRARP: + case SIOCGRARP: + case SIOCDRARP: + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return sock_do_ioctl(net, sock, cmd, arg); + } + + return -ENOIOCTLCMD; +} static long compat_sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) @@ -3193,6 +3202,9 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd, (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) ret = compat_wext_handle_ioctl(net, cmd, arg); + if (ret == -ENOIOCTLCMD) + ret = compat_sock_ioctl_trans(file, sock, cmd, arg); + return ret; } #endif -- cgit v1.2.3 From 9177efd3991e2cb3f5643a01d3be22121cab6efc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Nov 2009 08:09:09 +0000 Subject: net, compat_ioctl: handle more ioctls correctly The MII ioctls and SIOCSIFNAME need to go through ifsioc conversion, which they never did so far. Some others are not implemented in the native path, so we can just return -EINVAL directly. Add IFSLAVE ioctls to the EINVAL list and move it to the end to optimize the code path for the common case. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- net/socket.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index 901d709a7be..bfbde200b74 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3069,11 +3069,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, return do_siocgstamp(net, sock, cmd, argp); case SIOCGSTAMPNS: return do_siocgstampns(net, sock, cmd, argp); -/* Note SIOCRTMSG is no longer, so this is safe and - * the user would have seen just an -EINVAL anyways. */ - case SIOCRTMSG: - case SIOCGIFCOUNT: - return -EINVAL; case FIOSETOWN: case SIOCSPGRP: @@ -3107,8 +3102,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCSIFHWBROADCAST: case SIOCSHWTSTAMP: case SIOCDIFADDR: -/* case SIOCSARP: duplicate */ -/* case SIOCDARP: duplicate */ case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFDSTADDR: @@ -3121,7 +3114,12 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCSIFTXQLEN: case SIOCBRADDIF: case SIOCBRDELIF: + case SIOCSIFNAME: + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: return dev_ifsioc(net, sock, cmd, argp); + case ATM_GETLINKRATE32: case ATM_GETNAMES32: case ATM_GETTYPE32: @@ -3168,17 +3166,22 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCSARP: case SIOCGARP: case SIOCDARP: - case SIOCATMARK: - case SIOCSIFLINK: - case SIOCSIFNAME: + return sock_do_ioctl(net, sock, cmd, arg); + } + + /* Prevent warning from compat_sys_ioctl, these always + * result in -EINVAL in the native case anyway. */ + switch (cmd) { + case SIOCRTMSG: + case SIOCGIFCOUNT: case SIOCSRARP: case SIOCGRARP: case SIOCDRARP: - case SIOCGMIIPHY: - case SIOCGMIIREG: - case SIOCSMIIREG: - return sock_do_ioctl(net, sock, cmd, arg); + case SIOCSIFLINK: + case SIOCGIFSLAVE: + case SIOCSIFSLAVE: + return -EINVAL; } return -ENOIOCTLCMD; -- cgit v1.2.3 From d3bcfefaca27c1bfc8f740f5fff5b25d52ed1211 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 6 Nov 2009 22:17:25 -0800 Subject: net: Replace old style lock initializer SPIN_LOCK_UNLOCKED is deprecated. Use DEFINE_SPINLOCK instead. Signed-off-by: Thomas Gleixner Signed-off-by: David S. Miller --- net/core/drop_monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 0a113f26bc9..b8e9d3a8688 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -41,7 +41,7 @@ static void send_dm_alert(struct work_struct *unused); * netlink alerts */ static int trace_state = TRACE_OFF; -static spinlock_t trace_state_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(trace_state_lock); struct per_cpu_dm_data { struct work_struct dm_alert_work; -- cgit v1.2.3 From ecced8ba8759c16337fc6785d7bab8931ca55cf6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Nov 2009 04:37:26 +0000 Subject: net/appletalk: push down BKL into a atalk_dgram_ops Making the BKL usage explicit in appletalk makes it more obvious where it is used, reduces code size and helps getting rid of the BKL in common code. I did not analyse how to kill lock_kernel from appletalk entirely, this will involve either proving that it's not needed, or replacing with a proper mutex or spinlock, after finding out which data structures are protected by the lock. Cc: Arnaldo Carvalho de Melo Cc: David S. Miller Cc: Stephen Hemminger Cc: netdev@vger.kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- net/appletalk/ddp.c | 105 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 7cd08b45c52..31fca64d17a 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1055,11 +1055,13 @@ static int atalk_release(struct socket *sock) { struct sock *sk = sock->sk; + lock_kernel(); if (sk) { sock_orphan(sk); sock->sk = NULL; atalk_destroy_socket(sk); } + unlock_kernel(); return 0; } @@ -1135,6 +1137,7 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sockaddr_at *addr = (struct sockaddr_at *)uaddr; struct sock *sk = sock->sk; struct atalk_sock *at = at_sk(sk); + int err; if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_at)) @@ -1143,37 +1146,44 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr->sat_family != AF_APPLETALK) return -EAFNOSUPPORT; + lock_kernel(); if (addr->sat_addr.s_net == htons(ATADDR_ANYNET)) { struct atalk_addr *ap = atalk_find_primary(); + err = -EADDRNOTAVAIL; if (!ap) - return -EADDRNOTAVAIL; + goto out; at->src_net = addr->sat_addr.s_net = ap->s_net; at->src_node = addr->sat_addr.s_node= ap->s_node; } else { + err = -EADDRNOTAVAIL; if (!atalk_find_interface(addr->sat_addr.s_net, addr->sat_addr.s_node)) - return -EADDRNOTAVAIL; + goto out; at->src_net = addr->sat_addr.s_net; at->src_node = addr->sat_addr.s_node; } if (addr->sat_port == ATADDR_ANYPORT) { - int n = atalk_pick_and_bind_port(sk, addr); + err = atalk_pick_and_bind_port(sk, addr); - if (n < 0) - return n; + if (err < 0) + goto out; } else { at->src_port = addr->sat_port; + err = -EADDRINUSE; if (atalk_find_or_insert_socket(sk, addr)) - return -EADDRINUSE; + goto out; } sock_reset_flag(sk, SOCK_ZAPPED); - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* Set the address we talk to */ @@ -1183,6 +1193,7 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, struct sock *sk = sock->sk; struct atalk_sock *at = at_sk(sk); struct sockaddr_at *addr; + int err; sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; @@ -1207,12 +1218,15 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, #endif } + lock_kernel(); + err = -EBUSY; if (sock_flag(sk, SOCK_ZAPPED)) if (atalk_autobind(sk) < 0) - return -EBUSY; + goto out; + err = -ENETUNREACH; if (!atrtr_get_dev(&addr->sat_addr)) - return -ENETUNREACH; + goto out; at->dest_port = addr->sat_port; at->dest_net = addr->sat_addr.s_net; @@ -1220,7 +1234,10 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, sock->state = SS_CONNECTED; sk->sk_state = TCP_ESTABLISHED; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -1233,17 +1250,21 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, struct sockaddr_at sat; struct sock *sk = sock->sk; struct atalk_sock *at = at_sk(sk); + int err; + lock_kernel(); + err = -ENOBUFS; if (sock_flag(sk, SOCK_ZAPPED)) if (atalk_autobind(sk) < 0) - return -ENOBUFS; + goto out; *uaddr_len = sizeof(struct sockaddr_at); memset(&sat.sat_zero, 0, sizeof(sat.sat_zero)); if (peer) { + err = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + goto out; sat.sat_addr.s_net = at->dest_net; sat.sat_addr.s_node = at->dest_node; @@ -1254,9 +1275,23 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, sat.sat_port = at->src_port; } + err = 0; sat.sat_family = AF_APPLETALK; memcpy(uaddr, &sat, sizeof(sat)); - return 0; + +out: + unlock_kernel(); + return err; +} + +static unsigned int atalk_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ + int err; + lock_kernel(); + err = datagram_poll(file, sock, wait); + unlock_kernel(); + return err; } #if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE) @@ -1564,23 +1599,28 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr if (len > DDP_MAXSZ) return -EMSGSIZE; + lock_kernel(); if (usat) { + err = -EBUSY; if (sock_flag(sk, SOCK_ZAPPED)) if (atalk_autobind(sk) < 0) - return -EBUSY; + goto out; + err = -EINVAL; if (msg->msg_namelen < sizeof(*usat) || usat->sat_family != AF_APPLETALK) - return -EINVAL; + goto out; + err = -EPERM; /* netatalk didn't implement this check */ if (usat->sat_addr.s_node == ATADDR_BCAST && !sock_flag(sk, SOCK_BROADCAST)) { - return -EPERM; + goto out; } } else { + err = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + goto out; usat = &local_satalk; usat->sat_family = AF_APPLETALK; usat->sat_port = at->dest_port; @@ -1604,8 +1644,9 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr rt = atrtr_find(&at_hint); } + err = ENETUNREACH; if (!rt) - return -ENETUNREACH; + goto out; dev = rt->dev; @@ -1615,7 +1656,7 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr size += dev->hard_header_len; skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err); if (!skb) - return err; + goto out; skb->sk = sk; skb_reserve(skb, ddp_dl->header_length); @@ -1638,7 +1679,8 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); if (err) { kfree_skb(skb); - return -EFAULT; + err = -EFAULT; + goto out; } if (sk->sk_no_check == 1) @@ -1677,7 +1719,8 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr rt = atrtr_find(&at_lo); if (!rt) { kfree_skb(skb); - return -ENETUNREACH; + err = -ENETUNREACH; + goto out; } dev = rt->dev; skb->dev = dev; @@ -1697,7 +1740,9 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr } SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len); - return len; +out: + unlock_kernel(); + return err ? : len; } static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, @@ -1709,10 +1754,13 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr int copied = 0; int offset = 0; int err = 0; - struct sk_buff *skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + struct sk_buff *skb; + + lock_kernel(); + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err); if (!skb) - return err; + goto out; /* FIXME: use skb->cb to be able to use shared skbs */ ddp = ddp_hdr(skb); @@ -1740,6 +1788,9 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr } skb_free_datagram(sk, skb); /* Free the datagram. */ + +out: + unlock_kernel(); return err ? : copied; } @@ -1830,7 +1881,7 @@ static const struct net_proto_family atalk_family_ops = { .owner = THIS_MODULE, }; -static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = { +static const struct proto_ops atalk_dgram_ops = { .family = PF_APPLETALK, .owner = THIS_MODULE, .release = atalk_release, @@ -1839,7 +1890,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = atalk_getname, - .poll = datagram_poll, + .poll = atalk_poll, .ioctl = atalk_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = atalk_compat_ioctl, @@ -1854,8 +1905,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = { .sendpage = sock_no_sendpage, }; -SOCKOPS_WRAP(atalk_dgram, PF_APPLETALK); - static struct notifier_block ddp_notifier = { .notifier_call = ddp_device_event, }; -- cgit v1.2.3 From 83927ba069a65326f39991a02d6a49ba3b7cea44 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Nov 2009 04:37:27 +0000 Subject: net/ipx: push down BKL into a ipx_dgram_ops Making the BKL usage explicit in ipx makes it more obvious where it is used, reduces code size and helps getting rid of the BKL in common code. I did not analyse how to kill lock_kernel from ipx entirely, this will involve either proving that it's not needed, or replacing with a proper mutex or spinlock, after finding out which data structures are protected by the lock. Cc: Arnaldo Carvalho de Melo Cc: David S. Miller Cc: Stephen Hemminger Cc: netdev@vger.kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- net/ipx/af_ipx.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 96d193a2441..975c5a366e5 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1298,6 +1298,7 @@ static int ipx_setsockopt(struct socket *sock, int level, int optname, int opt; int rc = -EINVAL; + lock_kernel(); if (optlen != sizeof(int)) goto out; @@ -1312,6 +1313,7 @@ static int ipx_setsockopt(struct socket *sock, int level, int optname, ipx_sk(sk)->type = opt; rc = 0; out: + unlock_kernel(); return rc; } @@ -1323,6 +1325,7 @@ static int ipx_getsockopt(struct socket *sock, int level, int optname, int len; int rc = -ENOPROTOOPT; + lock_kernel(); if (!(level == SOL_IPX && optname == IPX_TYPE)) goto out; @@ -1343,6 +1346,7 @@ static int ipx_getsockopt(struct socket *sock, int level, int optname, rc = 0; out: + unlock_kernel(); return rc; } @@ -1391,6 +1395,7 @@ static int ipx_release(struct socket *sock) if (!sk) goto out; + lock_kernel(); if (!sock_flag(sk, SOCK_DEAD)) sk->sk_state_change(sk); @@ -1398,6 +1403,7 @@ static int ipx_release(struct socket *sock) sock->sk = NULL; sk_refcnt_debug_release(sk); ipx_destroy_socket(sk); + unlock_kernel(); out: return 0; } @@ -1425,7 +1431,8 @@ static __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc) return htons(socketNum); } -static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +static int __ipx_bind(struct socket *sock, + struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; struct ipx_sock *ipxs = ipx_sk(sk); @@ -1520,6 +1527,17 @@ out: return rc; } +static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + int rc; + + lock_kernel(); + rc = __ipx_bind(sock, uaddr, addr_len); + unlock_kernel(); + + return rc; +} + static int ipx_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { @@ -1532,6 +1550,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr, sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; + lock_kernel(); if (addr_len != sizeof(*addr)) goto out; addr = (struct sockaddr_ipx *)uaddr; @@ -1551,7 +1570,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr, IPX_NODE_LEN); #endif /* CONFIG_IPX_INTERN */ - rc = ipx_bind(sock, (struct sockaddr *)&uaddr, + rc = __ipx_bind(sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); if (rc) goto out; @@ -1578,6 +1597,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr, ipxrtr_put(rt); rc = 0; out: + unlock_kernel(); return rc; } @@ -1593,6 +1613,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, *uaddr_len = sizeof(struct sockaddr_ipx); + lock_kernel(); if (peer) { rc = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) @@ -1627,6 +1648,19 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, rc = 0; out: + unlock_kernel(); + return rc; +} + +static unsigned int ipx_datagram_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ + int rc; + + lock_kernel(); + rc = datagram_poll(file, sock, wait); + unlock_kernel(); + return rc; } @@ -1701,6 +1735,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock, int rc = -EINVAL; int flags = msg->msg_flags; + lock_kernel(); /* Socket gets bound below anyway */ /* if (sk->sk_zapped) return -EIO; */ /* Socket not bound */ @@ -1724,7 +1759,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock, memcpy(uaddr.sipx_node, ipxs->intrfc->if_node, IPX_NODE_LEN); #endif - rc = ipx_bind(sock, (struct sockaddr *)&uaddr, + rc = __ipx_bind(sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); if (rc) goto out; @@ -1752,6 +1787,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock, if (rc >= 0) rc = len; out: + unlock_kernel(); return rc; } @@ -1766,6 +1802,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; int copied, rc; + lock_kernel(); /* put the autobinding in */ if (!ipxs->port) { struct sockaddr_ipx uaddr; @@ -1780,7 +1817,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, memcpy(uaddr.sipx_node, ipxs->intrfc->if_node, IPX_NODE_LEN); #endif /* CONFIG_IPX_INTERN */ - rc = ipx_bind(sock, (struct sockaddr *)&uaddr, + rc = __ipx_bind(sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); if (rc) goto out; @@ -1824,6 +1861,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, out_free: skb_free_datagram(sk, skb); out: + unlock_kernel(); return rc; } @@ -1835,6 +1873,7 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) struct sock *sk = sock->sk; void __user *argp = (void __user *)arg; + lock_kernel(); switch (cmd) { case TIOCOUTQ: amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); @@ -1897,6 +1936,7 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) rc = -ENOIOCTLCMD; break; } + unlock_kernel(); return rc; } @@ -1934,7 +1974,7 @@ static const struct net_proto_family ipx_family_ops = { .owner = THIS_MODULE, }; -static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = { +static const struct proto_ops ipx_dgram_ops = { .family = PF_IPX, .owner = THIS_MODULE, .release = ipx_release, @@ -1943,7 +1983,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = ipx_getname, - .poll = datagram_poll, + .poll = ipx_datagram_poll, .ioctl = ipx_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ipx_compat_ioctl, @@ -1958,8 +1998,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = { .sendpage = sock_no_sendpage, }; -SOCKOPS_WRAP(ipx_dgram, PF_IPX); - static struct packet_type ipx_8023_packet_type __read_mostly = { .type = cpu_to_be16(ETH_P_802_3), .func = ipx_rcv, -- cgit v1.2.3 From 58a9d73202dd40076992154e9acfb98489cc8eab Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Nov 2009 00:38:01 -0800 Subject: net/irda: push BKL into proto_ops The irda driver uses the BKL implicitly in its protocol operations. Replace the wrapped proto_ops with explicit lock_kernel() calls makes the usage more obvious and shrinks the size of the object code. The calls t lock_kernel() should eventually all be replaced by other serialization methods, which requires finding out The calls t lock_kernel() should eventually all be replaced by other serialization methods, which requires finding out which data actually needs protection. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- net/irda/af_irda.c | 331 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 224 insertions(+), 107 deletions(-) (limited to 'net') diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index e73a0016c0a..10093aab617 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -714,11 +714,14 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr, struct sockaddr_irda saddr; struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); + int err; + lock_kernel(); memset(&saddr, 0, sizeof(saddr)); if (peer) { + err = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + goto out; saddr.sir_family = AF_IRDA; saddr.sir_lsap_sel = self->dtsap_sel; @@ -735,8 +738,10 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr, /* uaddr_len come to us uninitialised */ *uaddr_len = sizeof (struct sockaddr_irda); memcpy(uaddr, &saddr, *uaddr_len); - - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -748,21 +753,25 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr, static int irda_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + int err = -EOPNOTSUPP; IRDA_DEBUG(2, "%s()\n", __func__); + lock_kernel(); if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && (sk->sk_type != SOCK_DGRAM)) - return -EOPNOTSUPP; + goto out; if (sk->sk_state != TCP_LISTEN) { sk->sk_max_ack_backlog = backlog; sk->sk_state = TCP_LISTEN; - return 0; + err = 0; } +out: + unlock_kernel(); - return -EOPNOTSUPP; + return err; } /* @@ -783,36 +792,40 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len != sizeof(struct sockaddr_irda)) return -EINVAL; + lock_kernel(); #ifdef CONFIG_IRDA_ULTRA /* Special care for Ultra sockets */ if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA)) { self->pid = addr->sir_lsap_sel; + err = -EOPNOTSUPP; if (self->pid & 0x80) { IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__); - return -EOPNOTSUPP; + goto out; } err = irda_open_lsap(self, self->pid); if (err < 0) - return err; + goto out; /* Pretend we are connected */ sock->state = SS_CONNECTED; sk->sk_state = TCP_ESTABLISHED; + err = 0; - return 0; + goto out; } #endif /* CONFIG_IRDA_ULTRA */ self->ias_obj = irias_new_object(addr->sir_name, jiffies); + err = -ENOMEM; if (self->ias_obj == NULL) - return -ENOMEM; + goto out; err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); if (err < 0) { kfree(self->ias_obj->name); kfree(self->ias_obj); - return err; + goto out; } /* Register with LM-IAS */ @@ -820,7 +833,10 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) self->stsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->ias_obj); - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -839,22 +855,26 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) IRDA_DEBUG(2, "%s()\n", __func__); + lock_kernel(); err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0); if (err) - return err; + goto out; + err = -EINVAL; if (sock->state != SS_UNCONNECTED) - return -EINVAL; + goto out; if ((sk = sock->sk) == NULL) - return -EINVAL; + goto out; + err = -EOPNOTSUPP; if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && (sk->sk_type != SOCK_DGRAM)) - return -EOPNOTSUPP; + goto out; + err = -EINVAL; if (sk->sk_state != TCP_LISTEN) - return -EINVAL; + goto out; /* * The read queue this time is holding sockets ready to use @@ -875,18 +895,20 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) break; /* Non blocking operation */ + err = -EWOULDBLOCK; if (flags & O_NONBLOCK) - return -EWOULDBLOCK; + goto out; err = wait_event_interruptible(*(sk->sk_sleep), skb_peek(&sk->sk_receive_queue)); if (err) - return err; + goto out; } newsk = newsock->sk; + err = -EIO; if (newsk == NULL) - return -EIO; + goto out; newsk->sk_state = TCP_ESTABLISHED; @@ -894,10 +916,11 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) /* Now attach up the new socket */ new->tsap = irttp_dup(self->tsap, new); + err = -EPERM; /* value does not seem to make sense. -arnd */ if (!new->tsap) { IRDA_DEBUG(0, "%s(), dup failed!\n", __func__); kfree_skb(skb); - return -1; + goto out; } new->stsap_sel = new->tsap->stsap_sel; @@ -921,8 +944,10 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) newsock->state = SS_CONNECTED; irda_connect_response(new); - - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -955,28 +980,34 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, IRDA_DEBUG(2, "%s(%p)\n", __func__, self); + lock_kernel(); /* Don't allow connect for Ultra sockets */ + err = -ESOCKTNOSUPPORT; if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA)) - return -ESOCKTNOSUPPORT; + goto out; if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; - return 0; /* Connect completed during a ERESTARTSYS event */ + err = 0; + goto out; /* Connect completed during a ERESTARTSYS event */ } if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; - return -ECONNREFUSED; + err = -ECONNREFUSED; + goto out; } + err = -EISCONN; /* No reconnect on a seqpacket socket */ if (sk->sk_state == TCP_ESTABLISHED) - return -EISCONN; /* No reconnect on a seqpacket socket */ + goto out; sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; + err = -EINVAL; if (addr_len != sizeof(struct sockaddr_irda)) - return -EINVAL; + goto out; /* Check if user supplied any destination device address */ if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) { @@ -984,7 +1015,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name); if (err) { IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __func__); - return err; + goto out; } } else { /* Use the one provided by the user */ @@ -1000,7 +1031,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, err = irda_find_lsap_sel(self, addr->sir_name); if (err) { IRDA_DEBUG(0, "%s(), connect failed!\n", __func__); - return err; + goto out; } } else { /* Directly connect to the remote LSAP @@ -1025,29 +1056,35 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, self->max_sdu_size_rx, NULL); if (err) { IRDA_DEBUG(0, "%s(), connect failed!\n", __func__); - return err; + goto out; } /* Now the loop */ + err = -EINPROGRESS; if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) - return -EINPROGRESS; + goto out; + err = -ERESTARTSYS; if (wait_event_interruptible(*(sk->sk_sleep), (sk->sk_state != TCP_SYN_SENT))) - return -ERESTARTSYS; + goto out; if (sk->sk_state != TCP_ESTABLISHED) { sock->state = SS_UNCONNECTED; err = sock_error(sk); - return err? err : -ECONNRESET; + if (!err) + err = -ECONNRESET; + goto out; } sock->state = SS_CONNECTED; /* At this point, IrLMP has assigned our source address */ self->saddr = irttp_get_saddr(self->tsap); - - return 0; + err = 0; +out: + unlock_kernel(); + return err; } static struct proto irda_proto = { @@ -1193,6 +1230,7 @@ static int irda_release(struct socket *sock) if (sk == NULL) return 0; + lock_kernel(); lock_sock(sk); sk->sk_state = TCP_CLOSE; sk->sk_shutdown |= SEND_SHUTDOWN; @@ -1211,6 +1249,7 @@ static int irda_release(struct socket *sock) /* Destroy networking socket if we are the last reference on it, * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */ sock_put(sk); + unlock_kernel(); /* Notes on socket locking and deallocation... - Jean II * In theory we should put pairs of sock_hold() / sock_put() to @@ -1258,28 +1297,37 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); + lock_kernel(); /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT | - MSG_NOSIGNAL)) - return -EINVAL; + MSG_NOSIGNAL)) { + err = -EINVAL; + goto out; + } if (sk->sk_shutdown & SEND_SHUTDOWN) goto out_err; - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->sk_state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } self = irda_sk(sk); /* Check if IrTTP is wants us to slow down */ if (wait_event_interruptible(*(sk->sk_sleep), - (self->tx_flow != FLOW_STOP || sk->sk_state != TCP_ESTABLISHED))) - return -ERESTARTSYS; + (self->tx_flow != FLOW_STOP || sk->sk_state != TCP_ESTABLISHED))) { + err = -ERESTARTSYS; + goto out; + } /* Check if we are still connected */ - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->sk_state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } /* Check that we don't send out too big frames */ if (len > self->max_data_size) { @@ -1311,11 +1359,16 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); goto out_err; } + + unlock_kernel(); /* Tell client how much data we actually sent */ return len; - out_err: - return sk_stream_error(sk, msg->msg_flags, err); +out_err: + err = sk_stream_error(sk, msg->msg_flags, err); +out: + unlock_kernel(); + return err; } @@ -1336,13 +1389,14 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(4, "%s()\n", __func__); + lock_kernel(); if ((err = sock_error(sk)) < 0) - return err; + goto out; skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err); if (!skb) - return err; + goto out; skb_reset_transport_header(skb); copied = skb->len; @@ -1370,8 +1424,12 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock, irttp_flow_request(self->tsap, FLOW_START); } } - + unlock_kernel(); return copied; + +out: + unlock_kernel(); + return err; } /* @@ -1389,15 +1447,19 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(3, "%s()\n", __func__); + lock_kernel(); if ((err = sock_error(sk)) < 0) - return err; + goto out; + err = -EINVAL; if (sock->flags & __SO_ACCEPTCON) - return(-EINVAL); + goto out; + err =-EOPNOTSUPP; if (flags & MSG_OOB) - return -EOPNOTSUPP; + goto out; + err = 0; target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); timeo = sock_rcvtimeo(sk, noblock); @@ -1409,7 +1471,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock, if (skb == NULL) { DEFINE_WAIT(wait); - int ret = 0; + err = 0; if (copied >= target) break; @@ -1419,25 +1481,25 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock, /* * POSIX 1003.1g mandates this order. */ - ret = sock_error(sk); - if (ret) + err = sock_error(sk); + if (err) ; else if (sk->sk_shutdown & RCV_SHUTDOWN) ; else if (noblock) - ret = -EAGAIN; + err = -EAGAIN; else if (signal_pending(current)) - ret = sock_intr_errno(timeo); + err = sock_intr_errno(timeo); else if (sk->sk_state != TCP_ESTABLISHED) - ret = -ENOTCONN; + err = -ENOTCONN; else if (skb_peek(&sk->sk_receive_queue) == NULL) /* Wait process until data arrives */ schedule(); finish_wait(sk->sk_sleep, &wait); - if (ret) - return ret; + if (err) + goto out; if (sk->sk_shutdown & RCV_SHUTDOWN) break; @@ -1490,7 +1552,9 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock, } } - return copied; +out: + unlock_kernel(); + return err ? : copied; } /* @@ -1508,18 +1572,23 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; int err; + lock_kernel(); + IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); + err = -EINVAL; if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) - return -EINVAL; + goto out; if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); - return -EPIPE; + err = -EPIPE; + goto out; } + err = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + goto out; self = irda_sk(sk); @@ -1536,8 +1605,9 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); + err = -ENOBUFS; if (!skb) - return -ENOBUFS; + goto out; skb_reserve(skb, self->max_header_size); skb_reset_transport_header(skb); @@ -1547,7 +1617,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len); if (err) { kfree_skb(skb); - return err; + goto out; } /* @@ -1557,9 +1627,13 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, err = irttp_udata_request(self->tsap, skb); if (err) { IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); - return err; + goto out; } + unlock_kernel(); return len; +out: + unlock_kernel(); + return err; } /* @@ -1581,12 +1655,15 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); + lock_kernel(); + err = -EINVAL; if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) - return -EINVAL; + goto out; + err = -EPIPE; if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); - return -EPIPE; + goto out; } self = irda_sk(sk); @@ -1594,16 +1671,18 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, /* Check if an address was specified with sendto. Jean II */ if (msg->msg_name) { struct sockaddr_irda *addr = (struct sockaddr_irda *) msg->msg_name; + err = -EINVAL; /* Check address, extract pid. Jean II */ if (msg->msg_namelen < sizeof(*addr)) - return -EINVAL; + goto out; if (addr->sir_family != AF_IRDA) - return -EINVAL; + goto out; pid = addr->sir_lsap_sel; if (pid & 0x80) { IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto out; } } else { /* Check that the socket is properly bound to an Ultra @@ -1612,7 +1691,8 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, (sk->sk_state != TCP_ESTABLISHED)) { IRDA_DEBUG(0, "%s(), socket not bound to Ultra PID.\n", __func__); - return -ENOTCONN; + err = -ENOTCONN; + goto out; } /* Use PID from socket */ bound = 1; @@ -1631,8 +1711,9 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, skb = sock_alloc_send_skb(sk, len + self->max_header_size, msg->msg_flags & MSG_DONTWAIT, &err); + err = -ENOBUFS; if (!skb) - return -ENOBUFS; + goto out; skb_reserve(skb, self->max_header_size); skb_reset_transport_header(skb); @@ -1642,16 +1723,16 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len); if (err) { kfree_skb(skb); - return err; + goto out; } err = irlmp_connless_data_request((bound ? self->lsap : NULL), skb, pid); - if (err) { + if (err) IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); - return err; - } - return len; +out: + unlock_kernel(); + return err ? : len; } #endif /* CONFIG_IRDA_ULTRA */ @@ -1665,6 +1746,8 @@ static int irda_shutdown(struct socket *sock, int how) IRDA_DEBUG(1, "%s(%p)\n", __func__, self); + lock_kernel(); + sk->sk_state = TCP_CLOSE; sk->sk_shutdown |= SEND_SHUTDOWN; sk->sk_state_change(sk); @@ -1685,6 +1768,8 @@ static int irda_shutdown(struct socket *sock, int how) self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */ self->saddr = 0x0; /* so IrLMP assign us any link */ + unlock_kernel(); + return 0; } @@ -1700,6 +1785,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock, IRDA_DEBUG(4, "%s()\n", __func__); + lock_kernel(); poll_wait(file, sk->sk_sleep, wait); mask = 0; @@ -1747,18 +1833,34 @@ static unsigned int irda_poll(struct file * file, struct socket *sock, default: break; } + unlock_kernel(); return mask; } +static unsigned int irda_datagram_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ + int err; + + lock_kernel(); + err = datagram_poll(file, sock, wait); + unlock_kernel(); + + return err; +} + /* * Function irda_ioctl (sock, cmd, arg) */ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; + int err; IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd); + lock_kernel(); + err = -EINVAL; switch (cmd) { case TIOCOUTQ: { long amount; @@ -1766,9 +1868,8 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; - if (put_user(amount, (unsigned int __user *)arg)) - return -EFAULT; - return 0; + err = put_user(amount, (unsigned int __user *)arg); + break; } case TIOCINQ: { @@ -1777,15 +1878,14 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; - if (put_user(amount, (unsigned int __user *)arg)) - return -EFAULT; - return 0; + err = put_user(amount, (unsigned int __user *)arg); + break; } case SIOCGSTAMP: if (sk != NULL) - return sock_get_timestamp(sk, (struct timeval __user *)arg); - return -EINVAL; + err = sock_get_timestamp(sk, (struct timeval __user *)arg); + break; case SIOCGIFADDR: case SIOCSIFADDR: @@ -1797,14 +1897,14 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: - return -EINVAL; + break; default: IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__); - return -ENOIOCTLCMD; + err = -ENOIOCTLCMD; } + unlock_kernel(); - /*NOTREACHED*/ - return 0; + return err; } #ifdef CONFIG_COMPAT @@ -1826,7 +1926,7 @@ static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon * Set some options for the socket * */ -static int irda_setsockopt(struct socket *sock, int level, int optname, +static int __irda_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; @@ -2084,6 +2184,18 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, return 0; } +static int irda_setsockopt(struct socket *sock, int level, int optname, + char __user *optval, unsigned int optlen) +{ + int err; + + lock_kernel(); + err = __irda_setsockopt(sock, level, optname, optval, optlen); + unlock_kernel(); + + return err; +} + /* * Function irda_extract_ias_value(ias_opt, ias_value) * @@ -2136,7 +2248,7 @@ static int irda_extract_ias_value(struct irda_ias_set *ias_opt, /* * Function irda_getsockopt (sock, level, optname, optval, optlen) */ -static int irda_getsockopt(struct socket *sock, int level, int optname, +static int __irda_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; @@ -2464,13 +2576,25 @@ bed: return 0; } +static int irda_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) +{ + int err; + + lock_kernel(); + err = __irda_getsockopt(sock, level, optname, optval, optlen); + unlock_kernel(); + + return err; +} + static const struct net_proto_family irda_family_ops = { .family = PF_IRDA, .create = irda_create, .owner = THIS_MODULE, }; -static const struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = { +static const struct proto_ops irda_stream_ops = { .family = PF_IRDA, .owner = THIS_MODULE, .release = irda_release, @@ -2494,7 +2618,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = { .sendpage = sock_no_sendpage, }; -static const struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = { +static const struct proto_ops irda_seqpacket_ops = { .family = PF_IRDA, .owner = THIS_MODULE, .release = irda_release, @@ -2503,7 +2627,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = { .socketpair = sock_no_socketpair, .accept = irda_accept, .getname = irda_getname, - .poll = datagram_poll, + .poll = irda_datagram_poll, .ioctl = irda_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = irda_compat_ioctl, @@ -2518,7 +2642,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = { .sendpage = sock_no_sendpage, }; -static const struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = { +static const struct proto_ops irda_dgram_ops = { .family = PF_IRDA, .owner = THIS_MODULE, .release = irda_release, @@ -2527,7 +2651,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = { .socketpair = sock_no_socketpair, .accept = irda_accept, .getname = irda_getname, - .poll = datagram_poll, + .poll = irda_datagram_poll, .ioctl = irda_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = irda_compat_ioctl, @@ -2543,7 +2667,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = { }; #ifdef CONFIG_IRDA_ULTRA -static const struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = { +static const struct proto_ops irda_ultra_ops = { .family = PF_IRDA, .owner = THIS_MODULE, .release = irda_release, @@ -2552,7 +2676,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = irda_getname, - .poll = datagram_poll, + .poll = irda_datagram_poll, .ioctl = irda_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = irda_compat_ioctl, @@ -2568,13 +2692,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = { }; #endif /* CONFIG_IRDA_ULTRA */ -SOCKOPS_WRAP(irda_stream, PF_IRDA); -SOCKOPS_WRAP(irda_seqpacket, PF_IRDA); -SOCKOPS_WRAP(irda_dgram, PF_IRDA); -#ifdef CONFIG_IRDA_ULTRA -SOCKOPS_WRAP(irda_ultra, PF_IRDA); -#endif /* CONFIG_IRDA_ULTRA */ - /* * Function irsock_init (pro) * -- cgit v1.2.3 From 91774904fbf0fe1c71441dd8299342a4654f7103 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Nov 2009 04:37:29 +0000 Subject: net/x25: push BKL usage into x25_proto The x25 driver uses lock_kernel() implicitly through its proto_ops wrapper. The makes the usage explicit in order to get rid of that wrapper and to better document the usage of the BKL. The next step should be to get rid of the usage of the BKL in x25 entirely, which requires understanding what data structures need serialized accesses. Cc: Henner Eisen Cc: David S. Miller Cc: linux-x25@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- net/x25/af_x25.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 38e235f61e2..39ce03e07d1 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -415,6 +415,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname, struct sock *sk = sock->sk; int rc = -ENOPROTOOPT; + lock_kernel(); if (level != SOL_X25 || optname != X25_QBITINCL) goto out; @@ -429,6 +430,7 @@ static int x25_setsockopt(struct socket *sock, int level, int optname, x25_sk(sk)->qbitincl = !!opt; rc = 0; out: + unlock_kernel(); return rc; } @@ -438,6 +440,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname, struct sock *sk = sock->sk; int val, len, rc = -ENOPROTOOPT; + lock_kernel(); if (level != SOL_X25 || optname != X25_QBITINCL) goto out; @@ -458,6 +461,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname, val = x25_sk(sk)->qbitincl; rc = copy_to_user(optval, &val, len) ? -EFAULT : 0; out: + unlock_kernel(); return rc; } @@ -466,12 +470,14 @@ static int x25_listen(struct socket *sock, int backlog) struct sock *sk = sock->sk; int rc = -EOPNOTSUPP; + lock_kernel(); if (sk->sk_state != TCP_LISTEN) { memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN); sk->sk_max_ack_backlog = backlog; sk->sk_state = TCP_LISTEN; rc = 0; } + unlock_kernel(); return rc; } @@ -598,6 +604,7 @@ static int x25_release(struct socket *sock) struct sock *sk = sock->sk; struct x25_sock *x25; + lock_kernel(); if (!sk) goto out; @@ -628,6 +635,7 @@ static int x25_release(struct socket *sock) sock_orphan(sk); out: + unlock_kernel(); return 0; } @@ -635,18 +643,23 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; + int rc = 0; + lock_kernel(); if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_x25) || - addr->sx25_family != AF_X25) - return -EINVAL; + addr->sx25_family != AF_X25) { + rc = -EINVAL; + goto out; + } x25_sk(sk)->source_addr = addr->sx25_addr; x25_insert_socket(sk); sock_reset_flag(sk, SOCK_ZAPPED); SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); - - return 0; +out: + unlock_kernel(); + return rc; } static int x25_wait_for_connection_establishment(struct sock *sk) @@ -687,6 +700,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, struct x25_route *rt; int rc = 0; + lock_kernel(); lock_sock(sk); if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; @@ -764,6 +778,7 @@ out_put_route: x25_route_put(rt); out: release_sock(sk); + unlock_kernel(); return rc; } @@ -803,6 +818,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags) struct sk_buff *skb; int rc = -EINVAL; + lock_kernel(); if (!sk || sk->sk_state != TCP_LISTEN) goto out; @@ -830,6 +846,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags) out2: release_sock(sk); out: + unlock_kernel(); return rc; } @@ -839,10 +856,14 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr; struct sock *sk = sock->sk; struct x25_sock *x25 = x25_sk(sk); + int rc = 0; + lock_kernel(); if (peer) { - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->sk_state != TCP_ESTABLISHED) { + rc = -ENOTCONN; + goto out; + } sx25->sx25_addr = x25->dest_addr; } else sx25->sx25_addr = x25->source_addr; @@ -850,7 +871,21 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, sx25->sx25_family = AF_X25; *uaddr_len = sizeof(*sx25); - return 0; +out: + unlock_kernel(); + return rc; +} + +static unsigned int x25_datagram_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ + int rc; + + lock_kernel(); + rc = datagram_poll(file, sock, wait); + unlock_kernel(); + + return rc; } int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, @@ -1003,6 +1038,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, size_t size; int qbit = 0, rc = -EINVAL; + lock_kernel(); if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT)) goto out; @@ -1167,6 +1203,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, release_sock(sk); rc = len; out: + unlock_kernel(); return rc; out_kfree_skb: kfree_skb(skb); @@ -1187,6 +1224,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, unsigned char *asmptr; int rc = -ENOTCONN; + lock_kernel(); /* * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though @@ -1260,6 +1298,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, out_free_dgram: skb_free_datagram(sk, skb); out: + unlock_kernel(); return rc; } @@ -1271,6 +1310,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) void __user *argp = (void __user *)arg; int rc; + lock_kernel(); switch (cmd) { case TIOCOUTQ: { int amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); @@ -1473,6 +1513,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) rc = -ENOIOCTLCMD; break; } + unlock_kernel(); return rc; } @@ -1543,15 +1584,19 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, break; case SIOCGSTAMP: rc = -EINVAL; + lock_kernel(); if (sk) rc = compat_sock_get_timestamp(sk, (struct timeval __user*)argp); + unlock_kernel(); break; case SIOCGSTAMPNS: rc = -EINVAL; + lock_kernel(); if (sk) rc = compat_sock_get_timestampns(sk, (struct timespec __user*)argp); + unlock_kernel(); break; case SIOCGIFADDR: case SIOCSIFADDR: @@ -1570,16 +1615,22 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; + lock_kernel(); rc = x25_route_ioctl(cmd, argp); + unlock_kernel(); break; case SIOCX25GSUBSCRIP: + lock_kernel(); rc = compat_x25_subscr_ioctl(cmd, argp); + unlock_kernel(); break; case SIOCX25SSUBSCRIP: rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; + lock_kernel(); rc = compat_x25_subscr_ioctl(cmd, argp); + unlock_kernel(); break; case SIOCX25GFACILITIES: case SIOCX25SFACILITIES: @@ -1601,7 +1652,7 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, } #endif -static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { +static const struct proto_ops x25_proto_ops = { .family = AF_X25, .owner = THIS_MODULE, .release = x25_release, @@ -1610,7 +1661,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { .socketpair = sock_no_socketpair, .accept = x25_accept, .getname = x25_getname, - .poll = datagram_poll, + .poll = x25_datagram_poll, .ioctl = x25_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = compat_x25_ioctl, @@ -1625,8 +1676,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { .sendpage = sock_no_sendpage, }; -SOCKOPS_WRAP(x25_proto, AF_X25); - static struct packet_type x25_packet_type __read_mostly = { .type = cpu_to_be16(ETH_P_X25), .func = x25_lapb_receive_frame, -- cgit v1.2.3 From e0d087af725b09358336098a6b57bb7f90f96175 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Nov 2009 01:26:17 -0800 Subject: rtnetlink: Cleanups Pure cleanups patch Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 54 ++++++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 391a62cd9df..e2f3317f290 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -38,7 +38,6 @@ #include #include -#include #include #include @@ -53,8 +52,7 @@ #include #include -struct rtnl_link -{ +struct rtnl_link { rtnl_doit_func doit; rtnl_dumpit_func dumpit; }; @@ -65,6 +63,7 @@ void rtnl_lock(void) { mutex_lock(&rtnl_mutex); } +EXPORT_SYMBOL(rtnl_lock); void __rtnl_unlock(void) { @@ -76,16 +75,19 @@ void rtnl_unlock(void) /* This fellow will unlock it for us. */ netdev_run_todo(); } +EXPORT_SYMBOL(rtnl_unlock); int rtnl_trylock(void) { return mutex_trylock(&rtnl_mutex); } +EXPORT_SYMBOL(rtnl_trylock); int rtnl_is_locked(void) { return mutex_is_locked(&rtnl_mutex); } +EXPORT_SYMBOL(rtnl_is_locked); static struct rtnl_link *rtnl_msg_handlers[NPROTO]; @@ -168,7 +170,6 @@ int __rtnl_register(int protocol, int msgtype, return 0; } - EXPORT_SYMBOL_GPL(__rtnl_register); /** @@ -188,7 +189,6 @@ void rtnl_register(int protocol, int msgtype, "protocol = %d, message type = %d\n", protocol, msgtype); } - EXPORT_SYMBOL_GPL(rtnl_register); /** @@ -213,7 +213,6 @@ int rtnl_unregister(int protocol, int msgtype) return 0; } - EXPORT_SYMBOL_GPL(rtnl_unregister); /** @@ -230,7 +229,6 @@ void rtnl_unregister_all(int protocol) kfree(rtnl_msg_handlers[protocol]); rtnl_msg_handlers[protocol] = NULL; } - EXPORT_SYMBOL_GPL(rtnl_unregister_all); static LIST_HEAD(link_ops); @@ -253,7 +251,6 @@ int __rtnl_link_register(struct rtnl_link_ops *ops) list_add_tail(&ops->list, &link_ops); return 0; } - EXPORT_SYMBOL_GPL(__rtnl_link_register); /** @@ -271,7 +268,6 @@ int rtnl_link_register(struct rtnl_link_ops *ops) rtnl_unlock(); return err; } - EXPORT_SYMBOL_GPL(rtnl_link_register); static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) @@ -309,7 +305,6 @@ void __rtnl_link_unregister(struct rtnl_link_ops *ops) } list_del(&ops->list); } - EXPORT_SYMBOL_GPL(__rtnl_link_unregister); /** @@ -322,7 +317,6 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops) __rtnl_link_unregister(ops); rtnl_unlock(); } - EXPORT_SYMBOL_GPL(rtnl_link_unregister); static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind) @@ -427,12 +421,13 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data struct rtattr *rta; int size = RTA_LENGTH(attrlen); - rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size)); + rta = (struct rtattr *)skb_put(skb, RTA_ALIGN(size)); rta->rta_type = attrtype; rta->rta_len = size; memcpy(RTA_DATA(rta), data, attrlen); memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size); } +EXPORT_SYMBOL(__rta_fill); int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo) { @@ -454,6 +449,7 @@ int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid) return nlmsg_unicast(rtnl, skb, pid); } +EXPORT_SYMBOL(rtnl_unicast); void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, struct nlmsghdr *nlh, gfp_t flags) @@ -466,6 +462,7 @@ void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, nlmsg_notify(rtnl, skb, pid, group, report, flags); } +EXPORT_SYMBOL(rtnl_notify); void rtnl_set_sk_err(struct net *net, u32 group, int error) { @@ -473,6 +470,7 @@ void rtnl_set_sk_err(struct net *net, u32 group, int error) netlink_set_err(rtnl, 0, group, error); } +EXPORT_SYMBOL(rtnl_set_sk_err); int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) { @@ -501,6 +499,7 @@ nla_put_failure: nla_nest_cancel(skb, mx); return -EMSGSIZE; } +EXPORT_SYMBOL(rtnetlink_put_metrics); int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, u32 ts, u32 tsage, long expires, u32 error) @@ -520,14 +519,13 @@ int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci); } - EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); static void set_operstate(struct net_device *dev, unsigned char transition) { unsigned char operstate = dev->operstate; - switch(transition) { + switch (transition) { case IF_OPER_UP: if ((operstate == IF_OPER_DORMANT || operstate == IF_OPER_UNKNOWN) && @@ -728,6 +726,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_NET_NS_PID] = { .type = NLA_U32 }, [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, }; +EXPORT_SYMBOL(ifla_policy); static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { [IFLA_INFO_KIND] = { .type = NLA_STRING }, @@ -932,7 +931,8 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) goto errout; } - if ((err = validate_linkmsg(dev, tb)) < 0) + err = validate_linkmsg(dev, tb); + if (err < 0) goto errout; err = do_setlink(dev, ifm, tb, ifname, 0); @@ -985,7 +985,8 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, unsigned int real_num_queues = 1; if (ops->get_tx_queues) { - err = ops->get_tx_queues(net, tb, &num_queues, &real_num_queues); + err = ops->get_tx_queues(net, tb, &num_queues, + &real_num_queues); if (err) goto err; } @@ -1026,6 +1027,7 @@ err_free: err: return ERR_PTR(err); } +EXPORT_SYMBOL(rtnl_create_link); static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { @@ -1059,7 +1061,8 @@ replay: else dev = NULL; - if ((err = validate_linkmsg(dev, tb)) < 0) + err = validate_linkmsg(dev, tb); + if (err < 0) return err; if (tb[IFLA_LINKINFO]) { @@ -1210,7 +1213,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) if (s_idx == 0) s_idx = 1; - for (idx=1; idxnlh->nlmsg_type-RTM_BASE; if (idx < s_idx || idx == PF_PACKET) continue; @@ -1277,7 +1280,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) return 0; - family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family; + family = ((struct rtgenmsg *)NLMSG_DATA(nlh))->rtgen_family; if (family >= NPROTO) return -EAFNOSUPPORT; @@ -1310,7 +1313,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (nlh->nlmsg_len > min_len) { int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len); + struct rtattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); while (RTA_OK(attr, attrlen)) { unsigned flavor = attr->rta_type; @@ -1416,14 +1419,3 @@ void __init rtnetlink_init(void) rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); } -EXPORT_SYMBOL(__rta_fill); -EXPORT_SYMBOL(rtnetlink_put_metrics); -EXPORT_SYMBOL(rtnl_lock); -EXPORT_SYMBOL(rtnl_trylock); -EXPORT_SYMBOL(rtnl_unlock); -EXPORT_SYMBOL(rtnl_is_locked); -EXPORT_SYMBOL(rtnl_unicast); -EXPORT_SYMBOL(rtnl_notify); -EXPORT_SYMBOL(rtnl_set_sk_err); -EXPORT_SYMBOL(rtnl_create_link); -EXPORT_SYMBOL(ifla_policy); -- cgit v1.2.3 From fd5c00276127661f12e0315e3bbec41a1c0be376 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 6 Nov 2009 07:01:17 +0000 Subject: ipv6: avoid dev_hold()/dev_put() in rawv6_bind() Using RCU helps not touching device refcount in rawv6_bind() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/raw.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 818ef21ba76..926ce8eeffa 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -249,7 +249,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) /* Raw sockets are IPv6 only */ if (addr_type == IPV6_ADDR_MAPPED) - return(-EADDRNOTAVAIL); + return -EADDRNOTAVAIL; lock_sock(sk); @@ -257,6 +257,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (sk->sk_state != TCP_CLOSE) goto out; + rcu_read_lock(); /* Check if the address belongs to the host. */ if (addr_type != IPV6_ADDR_ANY) { struct net_device *dev = NULL; @@ -272,13 +273,13 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) /* Binding to link-local address requires an interface */ if (!sk->sk_bound_dev_if) - goto out; + goto out_unlock; - dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); - if (!dev) { - err = -ENODEV; - goto out; - } + err = -ENODEV; + dev = dev_get_by_index_rcu(sock_net(sk), + sk->sk_bound_dev_if); + if (!dev) + goto out_unlock; } /* ipv4 addr of the socket is invalid. Only the @@ -289,13 +290,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) err = -EADDRNOTAVAIL; if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, dev, 0)) { - if (dev) - dev_put(dev); - goto out; + goto out_unlock; } } - if (dev) - dev_put(dev); } inet->inet_rcv_saddr = inet->inet_saddr = v4addr; @@ -303,6 +300,8 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!(addr_type & IPV6_ADDR_MULTICAST)) ipv6_addr_copy(&np->saddr, &addr->sin6_addr); err = 0; +out_unlock: + rcu_read_unlock(); out: release_sock(sk); return err; -- cgit v1.2.3 From f7a3a1d8affe563846fc17f0e7c0cc1500190c57 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 4 Nov 2009 10:26:13 +0000 Subject: appletalk/ddp.c: Neaten checksum function atalk_sum_partial can now use the rol16 function in bitops.h Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/appletalk/ddp.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 31fca64d17a..b631cc73454 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -922,13 +922,8 @@ static unsigned long atalk_sum_partial(const unsigned char *data, { /* This ought to be unwrapped neatly. I'll trust gcc for now */ while (len--) { - sum += *data; - sum <<= 1; - if (sum & 0x10000) { - sum++; - sum &= 0xffff; - } - data++; + sum += *data++; + sum = rol16(sum, 1); } return sum; } -- cgit v1.2.3 From 81adee47dfb608df3ad0b91d230fb3cef75f0060 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 8 Nov 2009 00:53:51 -0800 Subject: net: Support specifying the network namespace upon device creation. There is no good reason to not support userspace specifying the network namespace during device creation, and it makes it easier to create a network device and pass it to a child network namespace with a well known name. We have to be careful to ensure that the target network namespace for the new device exists through the life of the call. To keep that logic clear I have factored out the network namespace grabbing logic into rtnl_link_get_net. In addtion we need to continue to pass the source network namespace to the rtnl_link_ops.newlink method so that we can find the base device source network namespace. Signed-off-by: Eric W. Biederman Acked-by: Eric Dumazet --- drivers/net/can/dev.c | 2 +- drivers/net/macvlan.c | 4 ++-- drivers/net/veth.c | 15 ++++++++++++--- include/net/rtnetlink.h | 8 +++++--- net/8021q/vlan_netlink.c | 4 ++-- net/core/rtnetlink.c | 38 +++++++++++++++++++++++++++----------- net/ipv4/ip_gre.c | 2 +- 7 files changed, 50 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index c3db111d2ff..5fe34d64ca2 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -674,7 +674,7 @@ nla_put_failure: return -EMSGSIZE; } -static int can_newlink(struct net_device *dev, +static int can_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { return -EOPNOTSUPP; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 20b7707f38e..d7dba3f6f76 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -504,7 +504,7 @@ static int macvlan_get_tx_queues(struct net *net, return 0; } -static int macvlan_newlink(struct net_device *dev, +static int macvlan_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -515,7 +515,7 @@ static int macvlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - lowerdev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); + lowerdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); if (lowerdev == NULL) return -ENODEV; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 9bed694cd21..2d657f2314c 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -340,7 +340,7 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[]) static struct rtnl_link_ops veth_link_ops; -static int veth_newlink(struct net_device *dev, +static int veth_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { int err; @@ -348,6 +348,7 @@ static int veth_newlink(struct net_device *dev, struct veth_priv *priv; char ifname[IFNAMSIZ]; struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; + struct net *net; /* * create and register peer first @@ -380,14 +381,22 @@ static int veth_newlink(struct net_device *dev, else snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); - peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp); - if (IS_ERR(peer)) + net = rtnl_link_get_net(src_net, tbp); + if (IS_ERR(net)) + return PTR_ERR(net); + + peer = rtnl_create_link(src_net, net, ifname, &veth_link_ops, tbp); + if (IS_ERR(peer)) { + put_net(net); return PTR_ERR(peer); + } if (tbp[IFLA_ADDRESS] == NULL) random_ether_addr(peer->dev_addr); err = register_netdevice(peer); + put_net(net); + net = NULL; if (err < 0) goto err_register_peer; diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index cd5af1f508f..48d3efcb088 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -55,7 +55,8 @@ struct rtnl_link_ops { int (*validate)(struct nlattr *tb[], struct nlattr *data[]); - int (*newlink)(struct net_device *dev, + int (*newlink)(struct net *src_net, + struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]); int (*changelink)(struct net_device *dev, @@ -83,8 +84,9 @@ extern void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops); extern int rtnl_link_register(struct rtnl_link_ops *ops); extern void rtnl_link_unregister(struct rtnl_link_ops *ops); -extern struct net_device *rtnl_create_link(struct net *net, char *ifname, - const struct rtnl_link_ops *ops, struct nlattr *tb[]); +extern struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); +extern struct net_device *rtnl_create_link(struct net *src_net, struct net *net, + char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]); extern const struct nla_policy ifla_policy[IFLA_MAX+1]; #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index a9150485019..3c9cf6a8e7f 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -119,7 +119,7 @@ static int vlan_get_tx_queues(struct net *net, return 0; } -static int vlan_newlink(struct net_device *dev, +static int vlan_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct vlan_dev_info *vlan = vlan_dev_info(dev); @@ -131,7 +131,7 @@ static int vlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - real_dev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); + real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); if (!real_dev) return -ENODEV; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e2f3317f290..33148a56819 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -733,6 +733,20 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { [IFLA_INFO_DATA] = { .type = NLA_NESTED }, }; +struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) +{ + struct net *net; + /* Examine the link attributes and figure out which + * network namespace we are talking about. + */ + if (tb[IFLA_NET_NS_PID]) + net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); + else + net = get_net(src_net); + return net; +} +EXPORT_SYMBOL(rtnl_link_get_net); + static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) { if (dev) { @@ -756,8 +770,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, int err; if (tb[IFLA_NET_NS_PID]) { - struct net *net; - net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); + struct net *net = rtnl_link_get_net(dev_net(dev), tb); if (IS_ERR(net)) { err = PTR_ERR(net); goto errout; @@ -976,8 +989,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return 0; } -struct net_device *rtnl_create_link(struct net *net, char *ifname, - const struct rtnl_link_ops *ops, struct nlattr *tb[]) +struct net_device *rtnl_create_link(struct net *src_net, struct net *net, + char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) { int err; struct net_device *dev; @@ -985,7 +998,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, unsigned int real_num_queues = 1; if (ops->get_tx_queues) { - err = ops->get_tx_queues(net, tb, &num_queues, + err = ops->get_tx_queues(src_net, tb, &num_queues, &real_num_queues); if (err) goto err; @@ -995,16 +1008,16 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, if (!dev) goto err; + dev_net_set(dev, net); + dev->rtnl_link_ops = ops; dev->real_num_tx_queues = real_num_queues; + if (strchr(dev->name, '%')) { err = dev_alloc_name(dev, dev->name); if (err < 0) goto err_free; } - dev_net_set(dev, net); - dev->rtnl_link_ops = ops; - if (tb[IFLA_MTU]) dev->mtu = nla_get_u32(tb[IFLA_MTU]); if (tb[IFLA_ADDRESS]) @@ -1083,6 +1096,7 @@ replay: if (1) { struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL; + struct net *dest_net; if (ops) { if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { @@ -1147,17 +1161,19 @@ replay: if (!ifname[0]) snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); - dev = rtnl_create_link(net, ifname, ops, tb); + dest_net = rtnl_link_get_net(net, tb); + dev = rtnl_create_link(net, dest_net, ifname, ops, tb); if (IS_ERR(dev)) err = PTR_ERR(dev); else if (ops->newlink) - err = ops->newlink(dev, tb, data); + err = ops->newlink(net, dev, tb, data); else err = register_netdevice(dev); - if (err < 0 && !IS_ERR(dev)) free_netdev(dev); + + put_net(dest_net); return err; } } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 71a3242fb7d..a7de9e3a8f1 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1483,7 +1483,7 @@ static void ipgre_tap_setup(struct net_device *dev) dev->features |= NETIF_F_NETNS_LOCAL; } -static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[], +static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct ip_tunnel *nt; -- cgit v1.2.3 From 415ce61aef5e9b2ed2516a13888c733bea15aedf Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sun, 8 Nov 2009 20:41:03 -0800 Subject: net/appletalk: using compat_ptr needs inclusion of linux/compat.h Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- net/appletalk/ddp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index b631cc73454..73ca4d52492 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -56,6 +56,7 @@ #include #include #include /* For TIOCOUTQ/INQ */ +#include #include #include #include -- cgit v1.2.3 From fdcc8aa953a1123a289791dd192090651036d593 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:17:05 +0000 Subject: udp: add a counter into udp_hslot Adds a counter in udp_hslot to keep an accurate count of sockets present in chain. This will permit to upcoming UDP lookup algo to chose the shortest chain when secondary hash is added. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/udp.h | 8 ++++++++ net/ipv4/udp.c | 3 +++ 2 files changed, 11 insertions(+) (limited to 'net') diff --git a/include/net/udp.h b/include/net/udp.h index 22aa2e7eb1d..9167281e47d 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -50,8 +50,16 @@ struct udp_skb_cb { }; #define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) +/** + * struct udp_hslot - UDP hash slot + * + * @head: head of list of sockets + * @count: number of sockets in 'head' list + * @lock: spinlock protecting changes to head/count + */ struct udp_hslot { struct hlist_nulls_head head; + int count; spinlock_t lock; } __attribute__((aligned(2 * sizeof(long)))); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d5e75e97651..ffc837643a0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -218,6 +218,7 @@ found: sk->sk_hash = snum; if (sk_unhashed(sk)) { sk_nulls_add_node_rcu(sk, &hslot->head); + hslot->count++; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); } error = 0; @@ -1053,6 +1054,7 @@ void udp_lib_unhash(struct sock *sk) spin_lock_bh(&hslot->lock); if (sk_nulls_del_node_init_rcu(sk)) { + hslot->count--; inet_sk(sk)->inet_num = 0; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); } @@ -1862,6 +1864,7 @@ void __init udp_table_init(struct udp_table *table, const char *name) } for (i = 0; i <= table->mask; i++) { INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); + table->hash[i].count = 0; spin_lock_init(&table->hash[i].lock); } } -- cgit v1.2.3 From d4cada4ae1c012815f95fa507eb86a0ae9d607d7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:17:30 +0000 Subject: udp: split sk_hash into two u16 hashes Union sk_hash with two u16 hashes for udp (no extra memory taken) One 16 bits hash on (local port) value (the previous udp 'hash') One 16 bits hash on (local address, local port) values, initialized but not yet used. This second hash is using jenkin hash for better distribution. Because the 'port' is xored later, a partial hash is performed on local address + net_hash_mix(net) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/udp.h | 2 ++ include/net/sock.h | 6 +++++- net/ipv4/udp.c | 25 +++++++++++++++++++------ net/ipv6/udp.c | 27 +++++++++++++++++++++++++-- 4 files changed, 51 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/linux/udp.h b/include/linux/udp.h index 832361e3e59..5b4b5274e68 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -55,6 +55,8 @@ static inline int udp_hashfn(struct net *net, unsigned num, unsigned mask) struct udp_sock { /* inet_sock has to be the first member */ struct inet_sock inet; +#define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0] +#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1] int pending; /* Any pending frames ? */ unsigned int corkflag; /* Cork is required */ __u16 encap_type; /* Is this an Encapsulation socket? */ diff --git a/include/net/sock.h b/include/net/sock.h index 55de3bd719a..827366b6268 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -109,6 +109,7 @@ struct net; * @skc_refcnt: reference count * @skc_tx_queue_mapping: tx queue number for this connection * @skc_hash: hash value used with various protocol lookup tables + * @skc_u16hashes: two u16 hash values used by UDP lookup tables * @skc_family: network address family * @skc_state: Connection state * @skc_reuse: %SO_REUSEADDR setting @@ -131,7 +132,10 @@ struct sock_common { atomic_t skc_refcnt; int skc_tx_queue_mapping; - unsigned int skc_hash; + union { + unsigned int skc_hash; + __u16 skc_u16hashes[2]; + }; unsigned short skc_family; volatile unsigned char skc_state; unsigned char skc_reuse; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ffc837643a0..af72de1c869 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -138,13 +138,14 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num, sk_nulls_for_each(sk2, node, &hslot->head) if (net_eq(sock_net(sk2), net) && sk2 != sk && - (bitmap || sk2->sk_hash == num) && + (bitmap || udp_sk(sk2)->udp_port_hash == num) && (!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && (*saddr_comp)(sk, sk2)) { if (bitmap) - __set_bit(sk2->sk_hash >> log, bitmap); + __set_bit(udp_sk(sk2)->udp_port_hash >> log, + bitmap); else return 1; } @@ -215,7 +216,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, } found: inet_sk(sk)->inet_num = snum; - sk->sk_hash = snum; + udp_sk(sk)->udp_port_hash = snum; + udp_sk(sk)->udp_portaddr_hash ^= snum; if (sk_unhashed(sk)) { sk_nulls_add_node_rcu(sk, &hslot->head); hslot->count++; @@ -238,8 +240,19 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) inet1->inet_rcv_saddr == inet2->inet_rcv_saddr)); } +static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr, + unsigned int port) +{ + return jhash_1word(saddr, net_hash_mix(net)) ^ port; +} + int udp_v4_get_port(struct sock *sk, unsigned short snum) { + /* precompute partial secondary hash */ + udp_sk(sk)->udp_portaddr_hash = + udp4_portaddr_hash(sock_net(sk), + inet_sk(sk)->inet_rcv_saddr, + 0); return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); } @@ -249,7 +262,7 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, { int score = -1; - if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && + if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && !ipv6_only_sock(sk)) { struct inet_sock *inet = inet_sk(sk); @@ -360,7 +373,7 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, struct inet_sock *inet = inet_sk(s); if (!net_eq(sock_net(s), net) || - s->sk_hash != hnum || + udp_sk(s)->udp_port_hash != hnum || (inet->inet_daddr && inet->inet_daddr != rmt_addr) || (inet->inet_dport != rmt_port && inet->inet_dport) || (inet->inet_rcv_saddr && @@ -1050,7 +1063,7 @@ void udp_lib_unhash(struct sock *sk) if (sk_hashed(sk)) { struct udp_table *udptable = sk->sk_prot->h.udp_table; struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk), - sk->sk_hash); + udp_sk(sk)->udp_port_hash); spin_lock_bh(&hslot->lock); if (sk_nulls_del_node_init_rcu(sk)) { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5bc7cdbf030..1e5fadd997b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -81,8 +81,30 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) return 0; } +static unsigned int udp6_portaddr_hash(struct net *net, + const struct in6_addr *addr6, + unsigned int port) +{ + unsigned int hash, mix = net_hash_mix(net); + + if (ipv6_addr_any(addr6)) + hash = jhash_1word(0, mix); + else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED) + hash = jhash_1word(addr6->s6_addr32[3], mix); + else + hash = jhash2(addr6->s6_addr32, 4, mix); + + return hash ^ port; +} + + int udp_v6_get_port(struct sock *sk, unsigned short snum) { + /* precompute partial secondary hash */ + udp_sk(sk)->udp_portaddr_hash = + udp6_portaddr_hash(sock_net(sk), + &inet6_sk(sk)->rcv_saddr, + 0); return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); } @@ -94,7 +116,7 @@ static inline int compute_score(struct sock *sk, struct net *net, { int score = -1; - if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && + if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); struct inet_sock *inet = inet_sk(sk); @@ -415,7 +437,8 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, if (!net_eq(sock_net(s), net)) continue; - if (s->sk_hash == num && s->sk_family == PF_INET6) { + if (udp_sk(s)->udp_port_hash == num && + s->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(s); if (inet->inet_dport) { if (inet->inet_dport != rmt_port) -- cgit v1.2.3 From 512615b6b843ff3ff5ad583f34c39b3f302f5f26 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:17:58 +0000 Subject: udp: secondary hash on (local port, local address) Extends udp_table to contain a secondary hash table. socket anchor for this second hash is free, because UDP doesnt use skc_bind_node : We define an union to hold both skc_bind_node & a new hlist_nulls_node udp_portaddr_node udp_lib_get_port() inserts sockets into second hash chain (additional cost of one atomic op) udp_lib_unhash() deletes socket from second hash chain (additional cost of one atomic op) Note : No spinlock lockdep annotation is needed, because lock for the secondary hash chain is always get after lock for primary hash chain. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/udp.h | 1 + include/net/sock.h | 8 ++++++-- include/net/udp.h | 22 ++++++++++++++++++++-- net/ipv4/udp.c | 31 ++++++++++++++++++++++++++----- 4 files changed, 53 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/linux/udp.h b/include/linux/udp.h index 5b4b5274e68..59f0ddf2d28 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -57,6 +57,7 @@ struct udp_sock { struct inet_sock inet; #define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0] #define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1] +#define udp_portaddr_node inet.sk.__sk_common.skc_portaddr_node int pending; /* Any pending frames ? */ unsigned int corkflag; /* Cork is required */ __u16 encap_type; /* Is this an Encapsulation socket? */ diff --git a/include/net/sock.h b/include/net/sock.h index 827366b6268..3f1a4804bb3 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -105,7 +105,7 @@ struct net; /** * struct sock_common - minimal network layer representation of sockets * @skc_node: main hash linkage for various protocol lookup tables - * @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol + * @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol * @skc_refcnt: reference count * @skc_tx_queue_mapping: tx queue number for this connection * @skc_hash: hash value used with various protocol lookup tables @@ -115,6 +115,7 @@ struct net; * @skc_reuse: %SO_REUSEADDR setting * @skc_bound_dev_if: bound device index if != 0 * @skc_bind_node: bind hash linkage for various protocol lookup tables + * @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol * @skc_prot: protocol handlers inside a network family * @skc_net: reference to the network namespace of this socket * @@ -140,7 +141,10 @@ struct sock_common { volatile unsigned char skc_state; unsigned char skc_reuse; int skc_bound_dev_if; - struct hlist_node skc_bind_node; + union { + struct hlist_node skc_bind_node; + struct hlist_nulls_node skc_portaddr_node; + }; struct proto *skc_prot; #ifdef CONFIG_NET_NS struct net *skc_net; diff --git a/include/net/udp.h b/include/net/udp.h index 9167281e47d..af41850f742 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -63,10 +63,19 @@ struct udp_hslot { spinlock_t lock; } __attribute__((aligned(2 * sizeof(long)))); +/** + * struct udp_table - UDP table + * + * @hash: hash table, sockets are hashed on (local port) + * @hash2: hash table, sockets are hashed on (local port, local address) + * @mask: number of slots in hash tables, minus 1 + * @log: log2(number of slots in hash table) + */ struct udp_table { struct udp_hslot *hash; - unsigned int mask; - unsigned int log; + struct udp_hslot *hash2; + unsigned int mask; + unsigned int log; }; extern struct udp_table udp_table; extern void udp_table_init(struct udp_table *, const char *); @@ -75,6 +84,15 @@ static inline struct udp_hslot *udp_hashslot(struct udp_table *table, { return &table->hash[udp_hashfn(net, num, table->mask)]; } +/* + * For secondary hash, net_hash_mix() is performed before calling + * udp_hashslot2(), this explains difference with udp_hashslot() + */ +static inline struct udp_hslot *udp_hashslot2(struct udp_table *table, + unsigned int hash) +{ + return &table->hash2[hash & table->mask]; +} /* Note: this must match 'valbool' in sock_setsockopt */ #define UDP_CSUM_NOXMIT 1 diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index af72de1c869..5f04216f35c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -163,7 +163,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2)) { - struct udp_hslot *hslot; + struct udp_hslot *hslot, *hslot2; struct udp_table *udptable = sk->sk_prot->h.udp_table; int error = 1; struct net *net = sock_net(sk); @@ -222,6 +222,13 @@ found: sk_nulls_add_node_rcu(sk, &hslot->head); hslot->count++; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + + hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); + spin_lock(&hslot2->lock); + hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node, + &hslot2->head); + hslot2->count++; + spin_unlock(&hslot2->lock); } error = 0; fail_unlock: @@ -1062,14 +1069,22 @@ void udp_lib_unhash(struct sock *sk) { if (sk_hashed(sk)) { struct udp_table *udptable = sk->sk_prot->h.udp_table; - struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk), - udp_sk(sk)->udp_port_hash); + struct udp_hslot *hslot, *hslot2; + + hslot = udp_hashslot(udptable, sock_net(sk), + udp_sk(sk)->udp_port_hash); + hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); spin_lock_bh(&hslot->lock); if (sk_nulls_del_node_init_rcu(sk)) { hslot->count--; inet_sk(sk)->inet_num = 0; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + + spin_lock(&hslot2->lock); + hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node); + hslot2->count--; + spin_unlock(&hslot2->lock); } spin_unlock_bh(&hslot->lock); } @@ -1857,7 +1872,7 @@ void __init udp_table_init(struct udp_table *table, const char *name) if (!CONFIG_BASE_SMALL) table->hash = alloc_large_system_hash(name, - sizeof(struct udp_hslot), + 2 * sizeof(struct udp_hslot), uhash_entries, 21, /* one slot per 2 MB */ 0, @@ -1869,17 +1884,23 @@ void __init udp_table_init(struct udp_table *table, const char *name) */ if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) { table->hash = kmalloc(UDP_HTABLE_SIZE_MIN * - sizeof(struct udp_hslot), GFP_KERNEL); + 2 * 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; } + table->hash2 = table->hash + (table->mask + 1); for (i = 0; i <= table->mask; i++) { INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); table->hash[i].count = 0; spin_lock_init(&table->hash[i].lock); } + for (i = 0; i <= table->mask; i++) { + INIT_HLIST_NULLS_HEAD(&table->hash2[i].head, i); + table->hash2[i].count = 0; + spin_lock_init(&table->hash2[i].lock); + } } void __init udp_init(void) -- cgit v1.2.3 From 5051ebd275de672b807c28d93002c2fb0514a3c9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:18:11 +0000 Subject: ipv4: udp: optimize unicast RX path We first locate the (local port) hash chain head If few sockets are in this chain, we proceed with previous lookup algo. If too many sockets are listed, we take a look at the secondary (port, address) hash chain we added in previous patch. We choose the shortest chain and proceed with a RCU lookup on the elected chain. But, if we chose (port, address) chain, and fail to find a socket on given address, we must try another lookup on (port, INADDR_ANY) chain to find socket not bound to a particular IP. -> No extra cost for typical setups, where the first lookup will probabbly be performed. RCU lookups everywhere, we dont acquire spinlock. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/udp.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5f04216f35c..dd7f3d20989 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -298,6 +298,91 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, return score; } +/* + * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num) + */ +#define SCORE2_MAX (1 + 2 + 2 + 2) +static inline int compute_score2(struct sock *sk, struct net *net, + __be32 saddr, __be16 sport, + __be32 daddr, unsigned int hnum, int dif) +{ + int score = -1; + + if (net_eq(sock_net(sk), net) && !ipv6_only_sock(sk)) { + struct inet_sock *inet = inet_sk(sk); + + if (inet->inet_rcv_saddr != daddr) + return -1; + if (inet->inet_num != hnum) + return -1; + + score = (sk->sk_family == PF_INET ? 1 : 0); + if (inet->inet_daddr) { + if (inet->inet_daddr != saddr) + return -1; + score += 2; + } + if (inet->inet_dport) { + if (inet->inet_dport != sport) + return -1; + score += 2; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + return -1; + score += 2; + } + } + return score; +} + +#define udp_portaddr_for_each_entry_rcu(__sk, node, list) \ + hlist_nulls_for_each_entry_rcu(__sk, node, list, __sk_common.skc_portaddr_node) + +/* called with read_rcu_lock() */ +static struct sock *udp4_lib_lookup2(struct net *net, + __be32 saddr, __be16 sport, + __be32 daddr, unsigned int hnum, int dif, + struct udp_hslot *hslot2, unsigned int slot2) +{ + struct sock *sk, *result; + struct hlist_nulls_node *node; + int score, badness; + +begin: + result = NULL; + badness = -1; + udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) { + score = compute_score2(sk, net, saddr, sport, + daddr, hnum, dif); + if (score > badness) { + result = sk; + badness = score; + if (score == SCORE2_MAX) + goto exact_match; + } + } + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != slot2) + goto begin; + + if (result) { +exact_match: + if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) + result = NULL; + else if (unlikely(compute_score2(result, net, saddr, sport, + daddr, hnum, dif) < badness)) { + sock_put(result); + goto begin; + } + } + return result; +} + /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ @@ -308,11 +393,35 @@ 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, udptable->mask); - struct udp_hslot *hslot = &udptable->hash[hash]; + unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); + struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; int score, badness; rcu_read_lock(); + if (hslot->count > 10) { + hash2 = udp4_portaddr_hash(net, daddr, hnum); + slot2 = hash2 & udptable->mask; + hslot2 = &udptable->hash2[slot2]; + if (hslot->count < hslot2->count) + goto begin; + + result = udp4_lib_lookup2(net, saddr, sport, + daddr, hnum, dif, + hslot2, slot2); + if (!result) { + hash2 = udp4_portaddr_hash(net, INADDR_ANY, hnum); + slot2 = hash2 & udptable->mask; + hslot2 = &udptable->hash2[slot2]; + if (hslot->count < hslot2->count) + goto begin; + + result = udp4_lib_lookup2(net, INADDR_ANY, sport, + daddr, hnum, dif, + hslot2, slot2); + } + rcu_read_unlock(); + return result; + } begin: result = NULL; badness = -1; @@ -329,7 +438,7 @@ begin: * not the expected one, we must restart lookup. * We probably met an item that was moved to another chain. */ - if (get_nulls_value(node) != hash) + if (get_nulls_value(node) != slot) goto begin; if (result) { -- cgit v1.2.3 From fddc17defa22d8caba1cdfb2e22b50bb4b9f35c0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:18:30 +0000 Subject: ipv6: udp: optimize unicast RX path We first locate the (local port) hash chain head If few sockets are in this chain, we proceed with previous lookup algo. If too many sockets are listed, we take a look at the secondary (port, address) hash chain. We choose the shortest chain and proceed with a RCU lookup on the elected chain. But, if we chose (port, address) chain, and fail to find a socket on given address, we must try another lookup on (port, in6addr_any) chain to find sockets not bound to a particular IP. -> No extra cost for typical setups, where the first lookup will probabbly be performed. RCU lookups everywhere, we dont acquire spinlock. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/udp.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 1e5fadd997b..f580cf92511 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -146,6 +146,88 @@ static inline int compute_score(struct sock *sk, struct net *net, return score; } +#define SCORE2_MAX (1 + 1 + 1) +static inline int compute_score2(struct sock *sk, struct net *net, + const struct in6_addr *saddr, __be16 sport, + const struct in6_addr *daddr, unsigned short hnum, + int dif) +{ + int score = -1; + + if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && + sk->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + struct inet_sock *inet = inet_sk(sk); + + if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) + return -1; + score = 0; + if (inet->inet_dport) { + if (inet->inet_dport != sport) + return -1; + score++; + } + if (!ipv6_addr_any(&np->daddr)) { + if (!ipv6_addr_equal(&np->daddr, saddr)) + return -1; + score++; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + return -1; + score++; + } + } + return score; +} + +#define udp_portaddr_for_each_entry_rcu(__sk, node, list) \ + hlist_nulls_for_each_entry_rcu(__sk, node, list, __sk_common.skc_portaddr_node) + +/* called with read_rcu_lock() */ +static struct sock *udp6_lib_lookup2(struct net *net, + const struct in6_addr *saddr, __be16 sport, + const struct in6_addr *daddr, unsigned int hnum, int dif, + struct udp_hslot *hslot2, unsigned int slot2) +{ + struct sock *sk, *result; + struct hlist_nulls_node *node; + int score, badness; + +begin: + result = NULL; + badness = -1; + udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) { + score = compute_score2(sk, net, saddr, sport, + daddr, hnum, dif); + if (score > badness) { + result = sk; + badness = score; + if (score == SCORE2_MAX) + goto exact_match; + } + } + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != slot2) + goto begin; + + if (result) { +exact_match: + if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) + result = NULL; + else if (unlikely(compute_score2(result, net, saddr, sport, + daddr, hnum, dif) < badness)) { + sock_put(result); + goto begin; + } + } + return result; +} + static struct sock *__udp6_lib_lookup(struct net *net, struct in6_addr *saddr, __be16 sport, struct in6_addr *daddr, __be16 dport, @@ -154,11 +236,35 @@ 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, udptable->mask); - struct udp_hslot *hslot = &udptable->hash[hash]; + unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); + struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; int score, badness; rcu_read_lock(); + if (hslot->count > 10) { + hash2 = udp6_portaddr_hash(net, daddr, hnum); + slot2 = hash2 & udptable->mask; + hslot2 = &udptable->hash2[slot2]; + if (hslot->count < hslot2->count) + goto begin; + + result = udp6_lib_lookup2(net, saddr, sport, + daddr, hnum, dif, + hslot2, slot2); + if (!result) { + hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum); + slot2 = hash2 & udptable->mask; + hslot2 = &udptable->hash2[slot2]; + if (hslot->count < hslot2->count) + goto begin; + + result = udp6_lib_lookup2(net, &in6addr_any, sport, + daddr, hnum, dif, + hslot2, slot2); + } + rcu_read_unlock(); + return result; + } begin: result = NULL; badness = -1; @@ -174,7 +280,7 @@ begin: * not the expected one, we must restart lookup. * We probably met an item that was moved to another chain. */ - if (get_nulls_value(node) != hash) + if (get_nulls_value(node) != slot) goto begin; if (result) { -- cgit v1.2.3 From 1240d1373cd7f874dd0f3057c3e9643e71ef75c6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:18:44 +0000 Subject: ipv4: udp: Optimise multicast reception UDP multicast rx path is a bit complex and can hold a spinlock for a long time. Using a small (32 or 64 entries) stack of socket pointers can help to perform expensive operations (skb_clone(), udp_queue_rcv_skb()) outside of the lock, in most cases. It's also a base for a future RCU conversion of multicast recption. Signed-off-by: Eric Dumazet Signed-off-by: Lucian Adrian Grijincu Signed-off-by: David S. Miller --- net/ipv4/udp.c | 76 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index dd7f3d20989..9d9072c6cce 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1329,49 +1329,73 @@ drop: return -1; } + +static void flush_stack(struct sock **stack, unsigned int count, + struct sk_buff *skb, unsigned int final) +{ + unsigned int i; + struct sk_buff *skb1 = NULL; + + for (i = 0; i < count; i++) { + if (likely(skb1 == NULL)) + skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); + + if (skb1 && udp_queue_rcv_skb(stack[i], skb1) <= 0) + skb1 = NULL; + } + if (unlikely(skb1)) + kfree_skb(skb1); +} + /* * Multicasts and broadcasts go to each listener. * - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. + * Note: called only from the BH handler context. */ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, struct udphdr *uh, __be32 saddr, __be32 daddr, struct udp_table *udptable) { - struct sock *sk; + struct sock *sk, *stack[256 / sizeof(struct sock *)]; struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); int dif; + unsigned int i, count = 0; spin_lock(&hslot->lock); sk = sk_nulls_head(&hslot->head); dif = skb->dev->ifindex; sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); - if (sk) { - struct sock *sknext = NULL; - - do { - struct sk_buff *skb1 = skb; - - sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, - daddr, uh->source, saddr, - dif); - if (sknext) - skb1 = skb_clone(skb, GFP_ATOMIC); - - if (skb1) { - int ret = udp_queue_rcv_skb(sk, skb1); - if (ret > 0) - /* we should probably re-process instead - * of dropping packets here. */ - kfree_skb(skb1); - } - sk = sknext; - } while (sknext); - } else - consume_skb(skb); + while (sk) { + stack[count++] = sk; + sk = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, + daddr, uh->source, saddr, dif); + if (unlikely(count == ARRAY_SIZE(stack))) { + if (!sk) + break; + flush_stack(stack, count, skb, ~0); + count = 0; + } + } + /* + * before releasing chain lock, we must take a reference on sockets + */ + for (i = 0; i < count; i++) + sock_hold(stack[i]); + spin_unlock(&hslot->lock); + + /* + * do the slow work with no lock held + */ + if (count) { + flush_stack(stack, count, skb, count - 1); + + for (i = 0; i < count; i++) + sock_put(stack[i]); + } else { + kfree_skb(skb); + } return 0; } -- cgit v1.2.3 From a1ab77f97ed03f5dae66ae4c64375beffab83772 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:18:52 +0000 Subject: ipv6: udp: Optimise multicast reception IPV6 UDP multicast rx path is a bit complex and can hold a spinlock for a long time. Using a small (32 or 64 entries) stack of socket pointers can help to perform expensive operations (skb_clone(), udp_queue_rcv_skb()) outside of the lock, in most cases. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/udp.c | 71 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f580cf92511..948e823d70c 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -569,6 +569,27 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, return NULL; } +static void flush_stack(struct sock **stack, unsigned int count, + struct sk_buff *skb, unsigned int final) +{ + unsigned int i; + struct sock *sk; + struct sk_buff *skb1; + + for (i = 0; i < count; i++) { + skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); + + if (skb1) { + sk = stack[i]; + bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb1); + else + sk_add_backlog(sk, skb1); + bh_unlock_sock(sk); + } + } +} /* * Note: called only from the BH handler context, * so we don't need to lock the hashes. @@ -577,41 +598,43 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, struct in6_addr *saddr, struct in6_addr *daddr, struct udp_table *udptable) { - struct sock *sk, *sk2; + struct sock *sk, *stack[256 / sizeof(struct sock *)]; const struct udphdr *uh = udp_hdr(skb); struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); int dif; + unsigned int i, count = 0; spin_lock(&hslot->lock); sk = sk_nulls_head(&hslot->head); dif = inet6_iif(skb); sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); - if (!sk) { - kfree_skb(skb); - goto out; - } - - sk2 = sk; - while ((sk2 = udp_v6_mcast_next(net, sk_nulls_next(sk2), uh->dest, daddr, - uh->source, saddr, dif))) { - struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); - if (buff) { - bh_lock_sock(sk2); - if (!sock_owned_by_user(sk2)) - udpv6_queue_rcv_skb(sk2, buff); - else - sk_add_backlog(sk2, buff); - bh_unlock_sock(sk2); + while (sk) { + stack[count++] = sk; + sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, + uh->source, saddr, dif); + if (unlikely(count == ARRAY_SIZE(stack))) { + if (!sk) + break; + flush_stack(stack, count, skb, ~0); + count = 0; } } - bh_lock_sock(sk); - if (!sock_owned_by_user(sk)) - udpv6_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); -out: + /* + * before releasing the lock, we must take reference on sockets + */ + for (i = 0; i < count; i++) + sock_hold(stack[i]); + spin_unlock(&hslot->lock); + + if (count) { + flush_stack(stack, count, skb, count - 1); + + for (i = 0; i < count; i++) + sock_put(stack[i]); + } else { + kfree_skb(skb); + } return 0; } -- cgit v1.2.3 From f6b8f32ca71406de718391369490f6b1e81fe0bb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2009 10:20:19 +0000 Subject: udp: multicast RX should increment SNMP/sk_drops counter in allocation failures When skb_clone() fails, we should increment sk_drops and SNMP counters. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/udp.c | 12 +++++++++++- net/ipv6/udp.c | 8 +++++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9d9072c6cce..d73e9170536 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1335,12 +1335,22 @@ static void flush_stack(struct sock **stack, unsigned int count, { unsigned int i; struct sk_buff *skb1 = NULL; + struct sock *sk; for (i = 0; i < count; i++) { + sk = stack[i]; if (likely(skb1 == NULL)) skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); - if (skb1 && udp_queue_rcv_skb(stack[i], skb1) <= 0) + if (!skb1) { + atomic_inc(&sk->sk_drops); + UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, + IS_UDPLITE(sk)); + UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, + IS_UDPLITE(sk)); + } + + if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0) skb1 = NULL; } if (unlikely(skb1)) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 948e823d70c..2915e1dad72 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -579,14 +579,20 @@ static void flush_stack(struct sock **stack, unsigned int count, for (i = 0; i < count; i++) { skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); + sk = stack[i]; if (skb1) { - sk = stack[i]; bh_lock_sock(sk); if (!sock_owned_by_user(sk)) udpv6_queue_rcv_skb(sk, skb1); else sk_add_backlog(sk, skb1); bh_unlock_sock(sk); + } else { + atomic_inc(&sk->sk_drops); + UDP6_INC_STATS_BH(sock_net(sk), + UDP_MIB_RCVBUFERRORS, IS_UDPLITE(sk)); + UDP6_INC_STATS_BH(sock_net(sk), + UDP_MIB_INERRORS, IS_UDPLITE(sk)); } } } -- cgit v1.2.3 From fab2532ba50b287647d95046c4f3b37bf6379d37 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sun, 8 Nov 2009 20:56:21 -0800 Subject: net, compat_ioctl: fix SIOCGMII ioctls SIOCGMIIPHY and SIOCGMIIREG return data through ifreq, so it needs to be converted on the way out as well. SIOCGIFPFLAGS is unused, but has the same problem in theory. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- net/socket.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index bfbde200b74..224e7f73fdf 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2746,7 +2746,10 @@ static int dev_ifsioc(struct net *net, struct socket *sock, case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: case SIOCGIFNETMASK: + case SIOCGIFPFLAGS: case SIOCGIFTXQLEN: + case SIOCGMIIPHY: + case SIOCGMIIREG: if (copy_to_user(uifr32, &ifr, sizeof(*uifr32))) return -EFAULT; break; -- cgit v1.2.3 From 7a50a240c495478179f01c9df4bd75e39cff79c7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sun, 8 Nov 2009 20:57:03 -0800 Subject: net/compat_ioctl: support SIOCWANDEV This adds compat_ioctl support for SIOCWANDEV, which has always been missing. The definition of struct compat_ifreq was missing an ifru_settings fields that is needed to support SIOCWANDEV, so add that and clean up the whitespace damage in the struct definition. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- include/linux/compat.h | 41 ++++++++++++++++++++++++----------------- net/socket.c | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/include/linux/compat.h b/include/linux/compat.h index 224c7a89617..ef68119a4fd 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -165,25 +165,32 @@ struct compat_ifmap { unsigned char port; }; +struct compat_if_settings +{ + unsigned int type; /* Type of physical device or protocol */ + unsigned int size; /* Size of the data allocated by the caller */ + compat_uptr_t ifs_ifsu; /* union of pointers */ +}; + struct compat_ifreq { - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - compat_int_t ifru_ivalue; - compat_int_t ifru_mtu; - struct compat_ifmap ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + compat_int_t ifru_ivalue; + compat_int_t ifru_mtu; + struct compat_ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; - compat_caddr_t ifru_data; - /* XXXX? ifru_settings should be here */ - } ifr_ifru; + compat_caddr_t ifru_data; + struct compat_if_settings ifru_settings; + } ifr_ifru; }; struct compat_ifconf { diff --git a/net/socket.c b/net/socket.c index 224e7f73fdf..befd9f5b162 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2627,6 +2627,27 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) return dev_ioctl(net, SIOCETHTOOL, ifr); } +static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) +{ + void __user *uptr; + compat_uptr_t uptr32; + struct ifreq __user *uifr; + + uifr = compat_alloc_user_space(sizeof (*uifr)); + if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) + return -EFAULT; + + if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu)) + return -EFAULT; + + uptr = compat_ptr(uptr32); + + if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc)) + return -EFAULT; + + return dev_ioctl(net, SIOCWANDEV, uifr); +} + static int bond_ioctl(struct net *net, unsigned int cmd, struct compat_ifreq __user *ifr32) { @@ -3058,6 +3079,8 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, return dev_ifconf(net, argp); case SIOCETHTOOL: return ethtool_ioctl(net, argp); + case SIOCWANDEV: + return compat_siocwandev(net, argp); case SIOCBONDENSLAVE: case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: -- cgit v1.2.3 From 9e0d57fd6dad37d72a3ca6db00ca8c76f2215454 Mon Sep 17 00:00:00 2001 From: Yury Polyanskiy Date: Sun, 8 Nov 2009 20:58:41 -0800 Subject: xfrm: SAD entries do not expire correctly after suspend-resume This fixes the following bug in the current implementation of net/xfrm: SAD entries timeouts do not count the time spent by the machine in the suspended state. This leads to the connectivity problems because after resuming local machine thinks that the SAD entry is still valid, while it has already been expired on the remote server. The cause of this is very simple: the timeouts in the net/xfrm are bound to the old mod_timer() timers. This patch reassigns them to the CLOCK_REALTIME hrtimer. I have been using this version of the patch for a few months on my machines without any problems. Also run a few stress tests w/o any issues. This version of the patch uses tasklet_hrtimer by Peter Zijlstra (commit 9ba5f0). This patch is against 2.6.31.4. Please CC me. Signed-off-by: Yury Polyanskiy Signed-off-by: David S. Miller --- include/net/xfrm.h | 5 ++++- net/xfrm/xfrm_state.c | 30 +++++++++++++++++------------- 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 7f38ef50995..93d184b91a8 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -19,6 +19,9 @@ #include #include #include + +#include + #ifdef CONFIG_XFRM_STATISTICS #include #endif @@ -198,7 +201,7 @@ struct xfrm_state { struct xfrm_stats stats; struct xfrm_lifetime_cur curlft; - struct timer_list timer; + struct tasklet_hrtimer mtimer; /* Last used time */ unsigned long lastused; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index f2f7c638083..e9ac0cec087 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include "xfrm_hash.h" @@ -352,7 +355,7 @@ static void xfrm_put_mode(struct xfrm_mode *mode) static void xfrm_state_gc_destroy(struct xfrm_state *x) { - del_timer_sync(&x->timer); + tasklet_hrtimer_cancel(&x->mtimer); del_timer_sync(&x->rtimer); kfree(x->aalg); kfree(x->ealg); @@ -398,9 +401,10 @@ static inline unsigned long make_jiffies(long secs) return secs*HZ; } -static void xfrm_timer_handler(unsigned long data) +static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me) { - struct xfrm_state *x = (struct xfrm_state*)data; + struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); + struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); struct net *net = xs_net(x); unsigned long now = get_seconds(); long next = LONG_MAX; @@ -451,8 +455,9 @@ static void xfrm_timer_handler(unsigned long data) if (warn) km_state_expired(x, 0, 0); resched: - if (next != LONG_MAX) - mod_timer(&x->timer, jiffies + make_jiffies(next)); + if (next != LONG_MAX){ + tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); + } goto out; @@ -474,6 +479,7 @@ expired: out: spin_unlock(&x->lock); + return HRTIMER_NORESTART; } static void xfrm_replay_timer_handler(unsigned long data); @@ -492,7 +498,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) INIT_HLIST_NODE(&x->bydst); INIT_HLIST_NODE(&x->bysrc); INIT_HLIST_NODE(&x->byspi); - setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); + tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, CLOCK_REALTIME, HRTIMER_MODE_ABS); setup_timer(&x->rtimer, xfrm_replay_timer_handler, (unsigned long)x); x->curlft.add_time = get_seconds(); @@ -843,8 +849,7 @@ found: hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); } x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; - x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; - add_timer(&x->timer); + tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); net->xfrm.state_num++; xfrm_hash_grow_check(net, x->bydst.next != NULL); } else { @@ -921,7 +926,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); } - mod_timer(&x->timer, jiffies + HZ); + tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); if (x->replay_maxage) mod_timer(&x->rtimer, jiffies + x->replay_maxage); @@ -1019,8 +1024,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family x->props.reqid = reqid; x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; xfrm_state_hold(x); - x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; - add_timer(&x->timer); + tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); list_add(&x->km.all, &net->xfrm.state_all); hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); h = xfrm_src_hash(net, daddr, saddr, family); @@ -1300,7 +1304,7 @@ out: memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); x1->km.dying = 0; - mod_timer(&x1->timer, jiffies + HZ); + tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); if (x1->curlft.use_time) xfrm_state_check_expire(x1); @@ -1325,7 +1329,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) if (x->curlft.bytes >= x->lft.hard_byte_limit || x->curlft.packets >= x->lft.hard_packet_limit) { x->km.state = XFRM_STATE_EXPIRED; - mod_timer(&x->timer, jiffies); + tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL); return -EINVAL; } -- cgit v1.2.3 From 6b0d07ba152893b40f1014a9db8da5aa564aa00e Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Mon, 9 Nov 2009 02:17:01 +0000 Subject: Phonet: put sockets in a hash table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/net/phonet/phonet.h | 1 + net/phonet/af_phonet.c | 1 + net/phonet/socket.c | 79 +++++++++++++++++++++++++++++++-------------- 3 files changed, 56 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h index fdb05fa0346..7b114079a51 100644 --- a/include/net/phonet/phonet.h +++ b/include/net/phonet/phonet.h @@ -46,6 +46,7 @@ static inline struct pn_sock *pn_sk(struct sock *sk) extern const struct proto_ops phonet_dgram_ops; +void pn_sock_init(void); struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa); void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb); void phonet_get_local_port_range(int *min, int *max); diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 3bd1be6b26f..8d3a55b4a30 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -481,6 +481,7 @@ static int __init phonet_init(void) if (err) return err; + pn_sock_init(); err = sock_register(&phonet_proto_family); if (err) { printk(KERN_ALERT diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 0412beb59a0..4112b6e1c48 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -45,13 +45,28 @@ static int pn_socket_release(struct socket *sock) return 0; } +#define PN_HASHSIZE 16 +#define PN_HASHMASK (PN_HASHSIZE-1) + + static struct { - struct hlist_head hlist; + struct hlist_head hlist[PN_HASHSIZE]; spinlock_t lock; -} pnsocks = { - .hlist = HLIST_HEAD_INIT, - .lock = __SPIN_LOCK_UNLOCKED(pnsocks.lock), -}; +} pnsocks; + +void __init pn_sock_init(void) +{ + unsigned i; + + for (i = 0; i < PN_HASHSIZE; i++) + INIT_HLIST_HEAD(pnsocks.hlist + i); + spin_lock_init(&pnsocks.lock); +} + +static struct hlist_head *pn_hash_list(u16 obj) +{ + return pnsocks.hlist + (obj & PN_HASHMASK); +} /* * Find address based on socket address, match only certain fields. @@ -64,10 +79,11 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) struct sock *rval = NULL; u16 obj = pn_sockaddr_get_object(spn); u8 res = spn->spn_resource; + struct hlist_head *hlist = pn_hash_list(obj); spin_lock_bh(&pnsocks.lock); - sk_for_each(sknode, node, &pnsocks.hlist) { + sk_for_each(sknode, node, hlist) { struct pn_sock *pn = pn_sk(sknode); BUG_ON(!pn->sobject); /* unbound socket */ @@ -99,31 +115,39 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) /* Deliver a broadcast packet (only in bottom-half) */ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb) { - struct hlist_node *node; - struct sock *sknode; + struct hlist_head *hlist = pnsocks.hlist; + unsigned h; spin_lock(&pnsocks.lock); - sk_for_each(sknode, node, &pnsocks.hlist) { - struct sk_buff *clone; + for (h = 0; h < PN_HASHSIZE; h++) { + struct hlist_node *node; + struct sock *sknode; - if (!net_eq(sock_net(sknode), net)) - continue; - if (!sock_flag(sknode, SOCK_BROADCAST)) - continue; + sk_for_each(sknode, node, hlist) { + struct sk_buff *clone; - clone = skb_clone(skb, GFP_ATOMIC); - if (clone) { - sock_hold(sknode); - sk_receive_skb(sknode, clone, 0); + if (!net_eq(sock_net(sknode), net)) + continue; + if (!sock_flag(sknode, SOCK_BROADCAST)) + continue; + + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) { + sock_hold(sknode); + sk_receive_skb(sknode, clone, 0); + } } + hlist++; } spin_unlock(&pnsocks.lock); } void pn_sock_hash(struct sock *sk) { + struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject); + spin_lock_bh(&pnsocks.lock); - sk_add_node(sk, &pnsocks.hlist); + sk_add_node(sk, hlist); spin_unlock_bh(&pnsocks.lock); } EXPORT_SYMBOL(pn_sock_hash); @@ -439,15 +463,20 @@ EXPORT_SYMBOL(pn_sock_get_port); static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos) { struct net *net = seq_file_net(seq); + struct hlist_head *hlist = pnsocks.hlist; struct hlist_node *node; struct sock *sknode; + unsigned h; - sk_for_each(sknode, node, &pnsocks.hlist) { - if (!net_eq(net, sock_net(sknode))) - continue; - if (!pos) - return sknode; - pos--; + for (h = 0; h < PN_HASHSIZE; h++) { + sk_for_each(sknode, node, hlist) { + if (!net_eq(net, sock_net(sknode))) + continue; + if (!pos) + return sknode; + pos--; + } + hlist++; } return NULL; } -- cgit v1.2.3 From b1704374fd525e50c44e1a03098728f64231a6f5 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Mon, 9 Nov 2009 04:06:40 +0000 Subject: Phonet: allocate and copy for pipe TX without sock lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/pep.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/phonet/pep.c b/net/phonet/pep.c index cbaa1d67d77..bdc17bdad36 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -843,7 +843,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { struct pep_sock *pn = pep_sk(sk); - struct sk_buff *skb = NULL; + struct sk_buff *skb; long timeo; int flags = msg->msg_flags; int err, done; @@ -851,6 +851,16 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR)) return -EOPNOTSUPP; + skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, + flags & MSG_DONTWAIT, &err); + if (!skb) + return -ENOBUFS; + + skb_reserve(skb, MAX_PHONET_HEADER + 3); + err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); + if (err < 0) + goto outfree; + lock_sock(sk); timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) { @@ -894,28 +904,13 @@ disabled: goto disabled; } - if (!skb) { - skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, - flags & MSG_DONTWAIT, &err); - if (skb == NULL) - goto out; - skb_reserve(skb, MAX_PHONET_HEADER + 3); - - if (sk->sk_state != TCP_ESTABLISHED || - !atomic_read(&pn->tx_credits)) - goto disabled; /* sock_alloc_send_skb might sleep */ - } - - err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); - if (err < 0) - goto out; - err = pipe_skb_send(sk, skb); if (err >= 0) err = len; /* success! */ skb = NULL; out: release_sock(sk); +outfree: kfree_skb(skb); return err; } -- cgit v1.2.3 From 30fff9231fad757c061285e347b33c5149c2c2e4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 9 Nov 2009 05:26:33 +0000 Subject: udp: bind() optimisation UDP bind() can be O(N^2) in some pathological cases. Thanks to secondary hash tables, we can make it O(N) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/udp.h | 6 +++++ include/net/udp.h | 3 ++- net/ipv4/udp.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++------ net/ipv6/udp.c | 14 +++++----- 4 files changed, 80 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/linux/udp.h b/include/linux/udp.h index 59f0ddf2d28..03f72a2ba02 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -88,6 +88,12 @@ static inline struct udp_sock *udp_sk(const struct sock *sk) return (struct udp_sock *)sk; } +#define udp_portaddr_for_each_entry(__sk, node, list) \ + hlist_nulls_for_each_entry(__sk, node, list, __sk_common.skc_portaddr_node) + +#define udp_portaddr_for_each_entry_rcu(__sk, node, list) \ + hlist_nulls_for_each_entry_rcu(__sk, node, list, __sk_common.skc_portaddr_node) + #define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) #endif diff --git a/include/net/udp.h b/include/net/udp.h index af41850f742..5348d80b25b 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -158,7 +158,8 @@ static inline void udp_lib_close(struct sock *sk, long timeout) } extern int udp_lib_get_port(struct sock *sk, unsigned short snum, - int (*)(const struct sock*,const struct sock*)); + int (*)(const struct sock *,const struct sock *), + unsigned int hash2_nulladdr); /* net/ipv4/udp.c */ extern int udp_get_port(struct sock *sk, unsigned short snum, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d73e9170536..1eaf57567eb 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -152,16 +152,49 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num, return 0; } +/* + * Note: we still hold spinlock of primary hash chain, so no other writer + * can insert/delete a socket with local_port == num + */ +static int udp_lib_lport_inuse2(struct net *net, __u16 num, + struct udp_hslot *hslot2, + struct sock *sk, + int (*saddr_comp)(const struct sock *sk1, + const struct sock *sk2)) +{ + struct sock *sk2; + struct hlist_nulls_node *node; + int res = 0; + + spin_lock(&hslot2->lock); + udp_portaddr_for_each_entry(sk2, node, &hslot2->head) + if (net_eq(sock_net(sk2), net) && + sk2 != sk && + (udp_sk(sk2)->udp_port_hash == num) && + (!sk2->sk_reuse || !sk->sk_reuse) && + (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if + || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && + (*saddr_comp)(sk, sk2)) { + res = 1; + break; + } + spin_unlock(&hslot2->lock); + return res; +} + /** * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up * @saddr_comp: AF-dependent comparison of bound local IP addresses + * @hash2_nulladdr: AF-dependant hash value in secondary hash chains, + * with NULL address */ int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*saddr_comp)(const struct sock *sk1, - const struct sock *sk2)) + const struct sock *sk2), + unsigned int hash2_nulladdr) { struct udp_hslot *hslot, *hslot2; struct udp_table *udptable = sk->sk_prot->h.udp_table; @@ -210,6 +243,30 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, } else { hslot = udp_hashslot(udptable, net, snum); spin_lock_bh(&hslot->lock); + if (hslot->count > 10) { + int exist; + unsigned int slot2 = udp_sk(sk)->udp_portaddr_hash ^ snum; + + slot2 &= udptable->mask; + hash2_nulladdr &= udptable->mask; + + hslot2 = udp_hashslot2(udptable, slot2); + if (hslot->count < hslot2->count) + goto scan_primary_hash; + + exist = udp_lib_lport_inuse2(net, snum, hslot2, + sk, saddr_comp); + if (!exist && (hash2_nulladdr != slot2)) { + hslot2 = udp_hashslot2(udptable, hash2_nulladdr); + exist = udp_lib_lport_inuse2(net, snum, hslot2, + sk, saddr_comp); + } + if (exist) + goto fail_unlock; + else + goto found; + } +scan_primary_hash: if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, saddr_comp, 0)) goto fail_unlock; @@ -255,12 +312,14 @@ static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr, int udp_v4_get_port(struct sock *sk, unsigned short snum) { + unsigned int hash2_nulladdr = + udp4_portaddr_hash(sock_net(sk), INADDR_ANY, snum); + unsigned int hash2_partial = + udp4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, 0); + /* precompute partial secondary hash */ - udp_sk(sk)->udp_portaddr_hash = - udp4_portaddr_hash(sock_net(sk), - inet_sk(sk)->inet_rcv_saddr, - 0); - return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); + udp_sk(sk)->udp_portaddr_hash = hash2_partial; + return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr); } static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, @@ -336,8 +395,6 @@ static inline int compute_score2(struct sock *sk, struct net *net, return score; } -#define udp_portaddr_for_each_entry_rcu(__sk, node, list) \ - hlist_nulls_for_each_entry_rcu(__sk, node, list, __sk_common.skc_portaddr_node) /* called with read_rcu_lock() */ static struct sock *udp4_lib_lookup2(struct net *net, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 2915e1dad72..f4c85b20005 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -100,12 +100,14 @@ static unsigned int udp6_portaddr_hash(struct net *net, int udp_v6_get_port(struct sock *sk, unsigned short snum) { + unsigned int hash2_nulladdr = + udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum); + unsigned int hash2_partial = + udp6_portaddr_hash(sock_net(sk), &inet6_sk(sk)->rcv_saddr, 0); + /* precompute partial secondary hash */ - udp_sk(sk)->udp_portaddr_hash = - udp6_portaddr_hash(sock_net(sk), - &inet6_sk(sk)->rcv_saddr, - 0); - return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); + udp_sk(sk)->udp_portaddr_hash = hash2_partial; + return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr); } static inline int compute_score(struct sock *sk, struct net *net, @@ -181,8 +183,6 @@ static inline int compute_score2(struct sock *sk, struct net *net, return score; } -#define udp_portaddr_for_each_entry_rcu(__sk, node, list) \ - hlist_nulls_for_each_entry_rcu(__sk, node, list, __sk_common.skc_portaddr_node) /* called with read_rcu_lock() */ static struct sock *udp6_lib_lookup2(struct net *net, -- cgit v1.2.3 From 13cfa97bef0f1172879f98307ac716acf3e9cea9 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Sun, 8 Nov 2009 05:51:19 +0000 Subject: net: netlink_getname, packet_getname -- use DECLARE_SOCKADDR guard Use guard DECLARE_SOCKADDR in a few more places which allow us to catch if the structure copied back is too big. Signed-off-by: Cyrill Gorcunov Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 2 +- net/packet/af_packet.c | 2 +- net/unix/af_unix.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index aea805c98da..f30d596dbc5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -708,7 +708,7 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, { struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); - struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; + DECLARE_SOCKADDR(struct sockaddr_nl *, nladdr, addr); nladdr->nl_family = AF_NETLINK; nladdr->nl_pad = 0; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 3304caa6534..c620bd9ae3d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1537,7 +1537,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, struct net_device *dev; struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); - struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr; + DECLARE_SOCKADDR(struct sockaddr_ll *, sll, uaddr); if (peer) return -EOPNOTSUPP; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 178d3af2a60..7553ea6edd8 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1259,7 +1259,7 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_ { struct sock *sk = sock->sk; struct unix_sock *u; - struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; + DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr); int err = 0; if (peer) { -- cgit v1.2.3 From 84d2697d9649339215675551eae28ba04068dea1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 9 Nov 2009 12:11:28 +0000 Subject: ipv6: speedup inet6_dump_ifinfo() When handling large number of netdevice, inet6_dump_ifinfo() is very slow because it has O(N^2) complexity. Instead of scanning one single list, we can use the 256 sub lists of the dev_index hash table, and RCU lookups. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 024bba30de2..f9f7fd6ee1f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3823,28 +3823,39 @@ nla_put_failure: static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); - int idx, err; - int s_idx = cb->args[0]; + int h, s_h; + int idx = 0, err, s_idx; struct net_device *dev; struct inet6_dev *idev; + struct hlist_head *head; + struct hlist_node *node; - read_lock(&dev_base_lock); - idx = 0; - for_each_netdev(net, dev) { - if (idx < s_idx) - goto cont; - if ((idev = in6_dev_get(dev)) == NULL) - goto cont; - err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI); - in6_dev_put(idev); - if (err <= 0) - break; + s_h = cb->args[0]; + s_idx = cb->args[1]; + + rcu_read_lock(); + for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { + idx = 0; + head = &net->dev_index_head[h]; + hlist_for_each_entry_rcu(dev, node, head, index_hlist) { + if (idx < s_idx) + goto cont; + idev = __in6_dev_get(dev); + if (!idev) + goto cont; + if (inet6_fill_ifinfo(skb, idev, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_NEWLINK, NLM_F_MULTI) <= 0) + goto out; cont: - idx++; + idx++; + } } - read_unlock(&dev_base_lock); - cb->args[0] = idx; +out: + rcu_read_unlock(); + cb->args[1] = idx; + cb->args[0] = h; return skb->len; } -- cgit v1.2.3 From bcd323262a94b14b84341982b90443a76a477861 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 9 Nov 2009 07:40:17 +0000 Subject: ipv6: Allow inet6_dump_addr() to handle more than 64 addresses Apparently, inet6_dump_addr() is not able to handle more than 64 ipv6 addresses per device. We must break from inner loops in case skb is full, or else cursor is put at the end of list. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f9f7fd6ee1f..0ab39fedd2d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3519,6 +3519,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, cb->nlh->nlmsg_seq, RTM_NEWADDR, NLM_F_MULTI); + if (err <= 0) + break; } break; case MULTICAST_ADDR: @@ -3532,6 +3534,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, cb->nlh->nlmsg_seq, RTM_GETMULTICAST, NLM_F_MULTI); + if (err <= 0) + break; } break; case ANYCAST_ADDR: @@ -3545,6 +3549,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, cb->nlh->nlmsg_seq, RTM_GETANYCAST, NLM_F_MULTI); + if (err <= 0) + break; } break; default: -- cgit v1.2.3 From 292f4f3ce4b57f17a667cb34c72bca081dcc0281 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 9 Nov 2009 08:42:01 +0000 Subject: sit: Clean up DF code by copying from IPIP This patch rearranges the SIT DF bit handling using the new IPIP DF code. The only externally visible effect should be the case where PMTU is enabled and the MTU is exactly 1280 bytes. In this case the previous code would send packets out with DF off while the new code would set the DF bit. This is inline with RFC 4213. Signed-off-by: Herbert Xu Thanks, Signed-off-by: David S. Miller --- net/ipv6/sit.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 2362a3397e9..b6e145a673a 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -637,6 +637,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, struct iphdr *tiph = &tunnel->parms.iph; struct ipv6hdr *iph6 = ipv6_hdr(skb); u8 tos = tunnel->parms.iph.tos; + __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *iph; /* Our new IP header */ @@ -726,25 +727,28 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, goto tx_error; } - if (tiph->frag_off) + if (df) { mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); - else - mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; - if (mtu < 68) { - stats->collisions++; - ip_rt_put(rt); - goto tx_error; - } - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; - if (tunnel->parms.iph.daddr && skb_dst(skb)) - skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); + if (mtu < 68) { + stats->collisions++; + ip_rt_put(rt); + goto tx_error; + } - if (skb->len > mtu) { - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); - ip_rt_put(rt); - goto tx_error; + if (mtu < IPV6_MIN_MTU) { + mtu = IPV6_MIN_MTU; + df = 0; + } + + if (tunnel->parms.iph.daddr && skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); + + if (skb->len > mtu) { + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); + ip_rt_put(rt); + goto tx_error; + } } if (tunnel->err_count > 0) { @@ -792,11 +796,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, iph = ip_hdr(skb); iph->version = 4; iph->ihl = sizeof(struct iphdr)>>2; - if (mtu > IPV6_MIN_MTU) - iph->frag_off = tiph->frag_off; - else - iph->frag_off = 0; - + iph->frag_off = df; iph->protocol = IPPROTO_IPV6; iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); iph->daddr = rt->rt_dst; -- cgit v1.2.3 From 856540ee3116ac04a49bc06c2f30f54dd3faf7db Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Mon, 9 Nov 2009 12:05:53 +0000 Subject: IPv6: use ipv6_addr_v4mapped() Change udp6_portaddr_hash() to use ipv6_addr_v4mapped() inline instead of ipv6_addr_type(). Signed-off-by: Brian Haley Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f4c85b20005..69ebdbe78c4 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -89,7 +89,7 @@ static unsigned int udp6_portaddr_hash(struct net *net, if (ipv6_addr_any(addr6)) hash = jhash_1word(0, mix); - else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED) + else if (ipv6_addr_v4mapped(addr6)) hash = jhash_1word(addr6->s6_addr32[3], mix); else hash = jhash2(addr6->s6_addr32, 4, mix); -- cgit v1.2.3 From 9e067597ee0e51a07bc158e9e2703ca676920e8b Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 10 Nov 2009 07:54:48 +0000 Subject: vlan: eliminate use of dev_base_lock Do not need to use read_lock(&dev_base_lock), use RCU instead. Signed-off-by: Stephen Hemminger Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlanproc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 6262c335f3c..9ec1f057c03 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -201,18 +201,17 @@ int vlan_proc_rem_dev(struct net_device *vlandev) /* start read of /proc/net/vlan/config */ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) + __acquires(rcu) { struct net_device *dev; struct net *net = seq_file_net(seq); loff_t i = 1; - read_lock(&dev_base_lock); - + rcu_read_lock(); if (*pos == 0) return SEQ_START_TOKEN; - for_each_netdev(net, dev) { + for_each_netdev_rcu(net, dev) { if (!is_vlan_dev(dev)) continue; @@ -234,7 +233,7 @@ static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) if (v == SEQ_START_TOKEN) dev = net_device_entry(&net->dev_base_head); - for_each_netdev_continue(net, dev) { + for_each_netdev_continue_rcu(net, dev) { if (!is_vlan_dev(dev)) continue; @@ -245,9 +244,9 @@ static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void vlan_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) + __releases(rcu) { - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int vlan_seq_show(struct seq_file *seq, void *v) -- cgit v1.2.3 From f1e9016da6d0f16551d90085758ae45d26826118 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 10 Nov 2009 07:54:49 +0000 Subject: net: use rcu for network scheduler API Use RCU to walk list of network devices in qdisc dump. This could be optimized for large number of devices. Signed-off-by: Stephen Hemminger Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_api.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 1acfd29cc82..876ba4bb6ae 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1279,9 +1279,10 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) s_idx = cb->args[0]; s_q_idx = q_idx = cb->args[1]; - read_lock(&dev_base_lock); + + rcu_read_lock(); idx = 0; - for_each_netdev(&init_net, dev) { + for_each_netdev_rcu(&init_net, dev) { struct netdev_queue *dev_queue; if (idx < s_idx) @@ -1302,7 +1303,7 @@ cont: } done: - read_unlock(&dev_base_lock); + rcu_read_unlock(); cb->args[0] = idx; cb->args[1] = q_idx; -- cgit v1.2.3 From fa918602b61a71b4a9f47861b7e65c70258516c1 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 10 Nov 2009 07:54:53 +0000 Subject: decnet: use RCU to find network devices When showing device statistics use RCU rather than read_lock(&dev_base_lock) Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/decnet/dn_dev.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index d82694d930b..b5ef237c8a7 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -856,9 +856,7 @@ int dn_dev_bind_default(__le16 *addr) dev = dn_dev_get_default(); last_chance: if (dev) { - read_lock(&dev_base_lock); rv = dn_dev_get_first(dev, addr); - read_unlock(&dev_base_lock); dev_put(dev); if (rv == 0 || dev == init_net.loopback_dev) return rv; @@ -1323,18 +1321,18 @@ static inline int is_dn_dev(struct net_device *dev) } static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(&dev_base_lock) + __acquires(rcu) { int i; struct net_device *dev; - read_lock(&dev_base_lock); + rcu_read_lock(); if (*pos == 0) return SEQ_START_TOKEN; i = 1; - for_each_netdev(&init_net, dev) { + for_each_netdev_rcu(&init_net, dev) { if (!is_dn_dev(dev)) continue; @@ -1355,7 +1353,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) if (v == SEQ_START_TOKEN) dev = net_device_entry(&init_net.dev_base_head); - for_each_netdev_continue(&init_net, dev) { + for_each_netdev_continue_rcu(&init_net, dev) { if (!is_dn_dev(dev)) continue; @@ -1366,9 +1364,9 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void dn_dev_seq_stop(struct seq_file *seq, void *v) - __releases(&dev_base_lock) + __releases(rcu) { - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static char *dn_type2asc(char type) -- cgit v1.2.3 From 61fbab77a843d2e772322ac130715cc9a98bf718 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 10 Nov 2009 07:54:55 +0000 Subject: IPV4: use rcu to walk list of devices in IGMP This also needs to be optimized for large number of devices. Signed-off-by: Stephen Hemminger Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d41e5de79a8..bd24f6560a4 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2311,7 +2311,7 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); state->in_dev = NULL; - for_each_netdev(net, state->dev) { + for_each_netdev_rcu(net, state->dev) { struct in_device *in_dev; in_dev = in_dev_get(state->dev); if (!in_dev) @@ -2361,9 +2361,9 @@ static struct ip_mc_list *igmp_mc_get_idx(struct seq_file *seq, loff_t pos) } static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) + __acquires(rcu) { - read_lock(&dev_base_lock); + rcu_read_lock(); return *pos ? igmp_mc_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } @@ -2379,7 +2379,7 @@ static void *igmp_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void igmp_mc_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) + __releases(rcu) { struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); if (likely(state->in_dev != NULL)) { @@ -2388,7 +2388,7 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v) state->in_dev = NULL; } state->dev = NULL; - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int igmp_mc_seq_show(struct seq_file *seq, void *v) @@ -2462,7 +2462,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) state->idev = NULL; state->im = NULL; - for_each_netdev(net, state->dev) { + for_each_netdev_rcu(net, state->dev) { struct in_device *idev; idev = in_dev_get(state->dev); if (unlikely(idev == NULL)) @@ -2528,8 +2528,9 @@ static struct ip_sf_list *igmp_mcf_get_idx(struct seq_file *seq, loff_t pos) } static void *igmp_mcf_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(rcu) { - read_lock(&dev_base_lock); + rcu_read_lock(); return *pos ? igmp_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } @@ -2545,6 +2546,7 @@ static void *igmp_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) + __releases(rcu) { struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); if (likely(state->im != NULL)) { @@ -2557,7 +2559,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) state->idev = NULL; } state->dev = NULL; - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int igmp_mcf_seq_show(struct seq_file *seq, void *v) -- cgit v1.2.3 From ff879eb611dba859c4349048a32789e8c82afa91 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 10 Nov 2009 07:54:56 +0000 Subject: CAN: use dev_get_by_index_rcu Use new function to avoid doing read_lock(). Signed-off-by: Stephen Hemminger Acked-by: Eric Dumazet Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller --- net/can/bcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/can/bcm.c b/net/can/bcm.c index c302c2ec959..e32af52238a 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -139,13 +139,13 @@ static char *bcm_proc_getifname(char *result, int ifindex) if (!ifindex) return "any"; - read_lock(&dev_base_lock); - dev = __dev_get_by_index(&init_net, ifindex); + rcu_read_lock(); + dev = dev_get_by_index_rcu(&init_net, ifindex); if (dev) strcpy(result, dev->name); else strcpy(result, "???"); - read_unlock(&dev_base_lock); + rcu_read_unlock(); return result; } -- cgit v1.2.3 From 3491707a070c1183c709516b2f876f798c7a9a84 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:39 +0000 Subject: mac80211: update meshconf IE This updates the Mesh Configuration IE according to the latest draft (3.03). Notable changes include the simplified protocol IDs. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 2 +- net/mac80211/ieee80211_i.h | 10 +++---- net/mac80211/mesh.c | 69 +++++++++++++++++++--------------------------- 3 files changed, 35 insertions(+), 46 deletions(-) (limited to 'net') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0aa83146749..50c684db33c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -115,7 +115,7 @@ #define IEEE80211_MAX_SSID_LEN 32 #define IEEE80211_MAX_MESH_ID_LEN 32 -#define IEEE80211_MESH_CONFIG_LEN 24 +#define IEEE80211_MESH_CONFIG_LEN 7 #define IEEE80211_QOS_CTL_LEN 2 #define IEEE80211_QOS_CTL_TID_MASK 0x000F diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1ef767366b7..1f4f88a8f80 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -361,15 +361,15 @@ struct ieee80211_if_mesh { u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; size_t mesh_id_len; /* Active Path Selection Protocol Identifier */ - u8 mesh_pp_id[4]; + u8 mesh_pp_id; /* Active Path Selection Metric Identifier */ - u8 mesh_pm_id[4]; + u8 mesh_pm_id; /* Congestion Control Mode Identifier */ - u8 mesh_cc_id[4]; + u8 mesh_cc_id; /* Synchronization Protocol Identifier */ - u8 mesh_sp_id[4]; + u8 mesh_sp_id; /* Authentication Protocol Identifier */ - u8 mesh_auth_id[4]; + u8 mesh_auth_id; /* Local mesh Destination Sequence Number */ u32 dsn; /* Last used PREQ ID */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a733890eb4..a49a3374acb 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -15,14 +15,14 @@ #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) -#define PP_OFFSET 1 /* Path Selection Protocol */ -#define PM_OFFSET 5 /* Path Selection Metric */ -#define CC_OFFSET 9 /* Congestion Control Mode */ -#define SP_OFFSET 13 /* Synchronization Protocol */ -#define AUTH_OFFSET 17 /* Authentication Protocol */ -#define CAPAB_OFFSET 22 -#define CAPAB_ACCEPT_PLINKS 0x80 -#define CAPAB_FORWARDING 0x10 +#define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */ +#define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */ +#define MESHCONF_CC_OFFSET 2 /* Congestion Control Mode */ +#define MESHCONF_SP_OFFSET 3 /* Synchronization Protocol */ +#define MESHCONF_AUTH_OFFSET 4 /* Authentication Protocol */ +#define MESHCONF_CAPAB_OFFSET 6 +#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 +#define MESHCONF_CAPAB_FORWARDING 0x08 #define TMR_RUNNING_HK 0 #define TMR_RUNNING_MP 1 @@ -85,11 +85,12 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ if (ifmsh->mesh_id_len == ie->mesh_id_len && memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && - memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && - memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && - memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 && - memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 && - memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0) + (ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&& + (ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&& + (ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&& + (ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&& + (ifmsh->mesh_auth_id == *(ie->mesh_config + + MESHCONF_AUTH_OFFSET))) return true; return false; @@ -102,7 +103,8 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) { - return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0; + return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) & + MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; } /** @@ -128,18 +130,11 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) void mesh_ids_set_default(struct ieee80211_if_mesh *sta) { - u8 oui[3] = {0x00, 0x0F, 0xAC}; - - memcpy(sta->mesh_pp_id, oui, sizeof(oui)); - memcpy(sta->mesh_pm_id, oui, sizeof(oui)); - memcpy(sta->mesh_cc_id, oui, sizeof(oui)); - memcpy(sta->mesh_sp_id, oui, sizeof(oui)); - memcpy(sta->mesh_auth_id, oui, sizeof(oui)); - sta->mesh_pp_id[sizeof(oui)] = 0; - sta->mesh_pm_id[sizeof(oui)] = 0; - sta->mesh_cc_id[sizeof(oui)] = 0xff; - sta->mesh_sp_id[sizeof(oui)] = 0xff; - sta->mesh_auth_id[sizeof(oui)] = 0x0; + sta->mesh_pp_id = 0; /* HWMP */ + sta->mesh_pm_id = 0; /* Airtime */ + sta->mesh_cc_id = 0; /* Disabled */ + sta->mesh_sp_id = 0; /* Neighbor Offset */ + sta->mesh_auth_id = 0; /* Disabled */ } int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) @@ -260,28 +255,21 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); *pos++ = WLAN_EID_MESH_CONFIG; *pos++ = IEEE80211_MESH_CONFIG_LEN; - /* Version */ - *pos++ = 1; /* Active path selection protocol ID */ - memcpy(pos, sdata->u.mesh.mesh_pp_id, 4); - pos += 4; + *pos++ = sdata->u.mesh.mesh_pp_id; /* Active path selection metric ID */ - memcpy(pos, sdata->u.mesh.mesh_pm_id, 4); - pos += 4; + *pos++ = sdata->u.mesh.mesh_pm_id; /* Congestion control mode identifier */ - memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); - pos += 4; + *pos++ = sdata->u.mesh.mesh_cc_id; /* Synchronization protocol identifier */ - memcpy(pos, sdata->u.mesh.mesh_sp_id, 4); - pos += 4; + *pos++ = sdata->u.mesh.mesh_sp_id; /* Authentication Protocol identifier */ - memcpy(pos, sdata->u.mesh.mesh_auth_id, 4); - pos += 4; + *pos++ = sdata->u.mesh.mesh_auth_id; /* Mesh Formation Info */ memset(pos, 0x00, 1); @@ -289,8 +277,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) /* Mesh capability */ sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); - *pos = CAPAB_FORWARDING; - *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00; + *pos = MESHCONF_CAPAB_FORWARDING; + *pos++ |= sdata->u.mesh.accepting_plinks ? + MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; *pos++ = 0x00; return; -- cgit v1.2.3 From a1935218da8964a033bdf68c591629741c94eeec Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:40 +0000 Subject: mac80211: set MESH_TTL to 31 Update the mesh time to live field to 31 according to draft 3.03. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index dd1c19319f0..9948107e831 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -174,7 +174,7 @@ struct mesh_rmc { #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) /* Default values, timeouts in ms */ -#define MESH_TTL 5 +#define MESH_TTL 31 #define MESH_MAX_RETR 3 #define MESH_RET_T 100 #define MESH_CONF_T 100 -- cgit v1.2.3 From 8f2fda9594f083981ad54c1994863875fe680925 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:41 +0000 Subject: mac80211: implement the meshconf formation info field The Mesh Configuration Formation Info field contains the number of neighbors. This means that the beacon must be updated every time a peer joins or leaves. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 9 ++++++--- net/mac80211/mesh_plink.c | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index a49a3374acb..79425182c29 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -223,6 +223,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) struct ieee80211_supported_band *sband; u8 *pos; int len, i, rate; + u8 neighbors; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; len = sband->n_bitrates; @@ -271,9 +272,11 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) /* Authentication Protocol identifier */ *pos++ = sdata->u.mesh.mesh_auth_id; - /* Mesh Formation Info */ - memset(pos, 0x00, 1); - pos += 1; + /* Mesh Formation Info - number of neighbors */ + neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks); + /* Number of neighbor mesh STAs or 15 whichever is smaller */ + neighbors = (neighbors > 15) ? 15 : neighbors; + *pos++ = neighbors << 1; /* Mesh capability */ sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ffcbad75e09..f98c8d23f58 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -65,6 +65,7 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); mesh_accept_plinks_update(sdata); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); } static inline @@ -72,6 +73,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); mesh_accept_plinks_update(sdata); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); } /** -- cgit v1.2.3 From 23c7a29cd020250646249592941261777cbeaf16 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:42 +0000 Subject: mac80211: fix typo in a comment Signed-off-by: Javier Cardona Signed-off-by: Rui Paulo Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index f98c8d23f58..418875246a0 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -79,7 +79,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) /** * mesh_plink_fsm_restart - restart a mesh peer link finite state machine * - * @sta: mes peer link to restart + * @sta: mesh peer link to restart * * Locking: this function must be called holding sta->lock */ -- cgit v1.2.3 From 0938393f02c5a4db75a6e38ee31645c974169bb5 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:43 +0000 Subject: mac80211: update peer link management IE and action frames Update the length and format of the peer link management action frames. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 2 +- net/mac80211/mesh.h | 2 +- net/mac80211/mesh_plink.c | 32 +++++++++++++++++--------------- net/mac80211/rx.c | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 79425182c29..63427d98321 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -553,7 +553,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_status *rx_status) { switch (mgmt->u.action.category) { - case PLINK_CATEGORY: + case MESH_PLINK_CATEGORY: mesh_rx_plink_frame(sdata, mgmt, len, rx_status); break; case MESH_PATH_SEL_CATEGORY: diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 9948107e831..536d5c07fd1 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -206,7 +206,7 @@ struct mesh_rmc { #define MESH_MAX_MPATHS 1024 /* Pending ANA approval */ -#define PLINK_CATEGORY 30 +#define MESH_PLINK_CATEGORY 30 #define MESH_PATH_SEL_CATEGORY 32 /* Public interfaces */ diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 418875246a0..8a54bc836c9 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -18,9 +18,8 @@ #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) #endif -#define PLINK_GET_FRAME_SUBTYPE(p) (p) -#define PLINK_GET_LLID(p) (p + 1) -#define PLINK_GET_PLID(p) (p + 3) +#define PLINK_GET_LLID(p) (p + 4) +#define PLINK_GET_PLID(p) (p + 6) #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ jiffies + HZ * t / 1000)) @@ -154,6 +153,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); struct ieee80211_mgmt *mgmt; bool include_plid = false; + static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; u8 *pos; int ie_len; @@ -171,7 +171,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ - mgmt->u.action.category = PLINK_CATEGORY; + mgmt->u.action.category = MESH_PLINK_CATEGORY; mgmt->u.action.u.plink_action.action_code = action; if (action == PLINK_CLOSE) @@ -189,18 +189,18 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, /* Add Peer Link Management element */ switch (action) { case PLINK_OPEN: - ie_len = 3; + ie_len = 6; break; case PLINK_CONFIRM: - ie_len = 5; + ie_len = 8; include_plid = true; break; case PLINK_CLOSE: default: if (!plid) - ie_len = 5; + ie_len = 8; else { - ie_len = 7; + ie_len = 10; include_plid = true; } break; @@ -209,7 +209,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PEER_LINK; *pos++ = ie_len; - *pos++ = action; + memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto)); + pos += 4; memcpy(pos, &llid, 2); if (include_plid) { pos += 2; @@ -419,12 +420,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } - ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link)); + ftype = mgmt->u.action.u.plink_action.action_code; ie_len = elems.peer_link_len; - if ((ftype == PLINK_OPEN && ie_len != 3) || - (ftype == PLINK_CONFIRM && ie_len != 5) || - (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) { - mpl_dbg("Mesh plink: incorrect plink ie length\n"); + if ((ftype == PLINK_OPEN && ie_len != 6) || + (ftype == PLINK_CONFIRM && ie_len != 8) || + (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) { + mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", + ftype, ie_len); return; } @@ -436,7 +438,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m * from the point of view of this host. */ memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); - if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) + if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10)) memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); rcu_read_lock(); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 28316b2a585..4066570dd41 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -507,7 +507,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_is_action(hdr->frame_control)) { mgmt = (struct ieee80211_mgmt *)hdr; - if (mgmt->u.action.category != PLINK_CATEGORY) + if (mgmt->u.action.category != MESH_PLINK_CATEGORY) return RX_DROP_MONITOR; return RX_CONTINUE; } -- cgit v1.2.3 From 095de01325962e7574d5793193c6f3ae9a175aab Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:44 +0000 Subject: mac80211: update the format of path selection frames Update the format of path selection frames according to latest draft (3.03). Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh.h | 1 + net/mac80211/mesh_hwmp.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 536d5c07fd1..2fd3e200a06 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -208,6 +208,7 @@ struct mesh_rmc { /* Pending ANA approval */ #define MESH_PLINK_CATEGORY 30 #define MESH_PATH_SEL_CATEGORY 32 +#define MESH_PATH_SEL_ACTION 0 /* Public interfaces */ /* Various */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 29b82e98eff..c291cdb7531 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -105,7 +105,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; - mgmt->u.action.u.mesh_action.action_code = action; + mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; switch (action) { case MPATH_PREQ: -- cgit v1.2.3 From 27db2e423fdeae8815087677261ab72cca7b3c28 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:45 +0000 Subject: mac80211: add MAC80211_VERBOSE_MHWMP_DEBUG Add MAC80211_VERBOSE_MHWMP_DEBUG, a debugging option for HWMP frame processing. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 13 +++++++++++++ net/mac80211/mesh_hwmp.c | 19 +++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 4d5543af312..a10d508b07e 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -194,6 +194,19 @@ config MAC80211_VERBOSE_MPL_DEBUG Do not select this option. +config MAC80211_VERBOSE_MHWMP_DEBUG + bool "Verbose mesh HWMP routing debugging" + depends on MAC80211_DEBUG_MENU + depends on MAC80211_MESH + ---help--- + Selecting this option causes mac80211 to print out very + verbose mesh routing (HWMP) debugging messages (when mac80211 + is taking part in a mesh network). + It should not be selected on production systems as those + messages are remotely triggerable. + + Do not select this option. + config MAC80211_DEBUG_COUNTERS bool "Extra statistics for TX/RX debugging" depends on MAC80211_DEBUG_MENU diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c291cdb7531..6dbaec53653 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -9,6 +9,12 @@ #include "mesh.h" +#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG +#define mhwmp_dbg(fmt, args...) printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args) +#else +#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0) +#endif + #define TEST_FRAME_LEN 8192 #define MAX_METRIC 0xffffffff #define ARITH_SHIFT 8 @@ -109,11 +115,13 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, switch (action) { case MPATH_PREQ: + mhwmp_dbg("sending PREQ\n"); ie_len = 37; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREQ; break; case MPATH_PREP: + mhwmp_dbg("sending PREP\n"); ie_len = 31; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; @@ -432,6 +440,8 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); dst_flags = PREQ_IE_DST_F(preq_elem); + mhwmp_dbg("received PREQ\n"); + if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { forward = false; reply = true; @@ -467,13 +477,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, if (reply) { lifetime = PREQ_IE_LIFETIME(preq_elem); ttl = ifmsh->mshcfg.dot11MeshTTL; - if (ttl != 0) + if (ttl != 0) { + mhwmp_dbg("replying to the PREQ\n"); mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, cpu_to_le32(dst_dsn), 0, orig_addr, cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); - else + } else ifmsh->mshstats.dropped_frames_ttl++; } @@ -661,7 +672,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); if (!preq_node) { - printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); + mhwmp_dbg("could not allocate PREQ node\n"); return; } @@ -670,7 +681,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock(&ifmsh->mesh_preq_queue_lock); kfree(preq_node); if (printk_ratelimit()) - printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); + mhwmp_dbg("PREQ node queue full\n"); return; } -- cgit v1.2.3 From dbb81c428bf534fcfe94102acca50f6d56504999 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:46 +0000 Subject: mac80211: allow processing of more than one HWMP IE Since the HWMP IEs are now all optional and the action code is fixed, allow the HWMP code to find and process each IE on the path selection action frames. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 6dbaec53653..e67e812f78e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -192,7 +192,7 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; - mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; + mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; ie_len = 12; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PERR; @@ -277,7 +277,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, */ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, - u8 *hwmp_ie) + u8 *hwmp_ie, enum mpath_frame_type action) { struct ieee80211_local *local = sdata->local; struct mesh_path *mpath; @@ -288,7 +288,6 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, unsigned long orig_lifetime, exp_time; u32 last_hop_metric, new_metric; bool process = true; - u8 action = mgmt->u.action.u.mesh_action.action_code; rcu_read_lock(); sta = sta_info_get(local, mgmt->sa); @@ -443,6 +442,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, mhwmp_dbg("received PREQ\n"); if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { + mhwmp_dbg("PREQ is for us\n"); forward = false; reply = true; metric = 0; @@ -498,6 +498,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, ifmsh->mshstats.dropped_frames_ttl++; return; } + mhwmp_dbg("forwarding the PREQ\n"); --ttl; flags = PREQ_IE_FLAGS(preq_elem); preq_id = PREQ_IE_PREQ_ID(preq_elem); @@ -524,6 +525,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, u8 next_hop[ETH_ALEN]; u32 dst_dsn, orig_dsn, lifetime; + mhwmp_dbg("received PREP\n"); + /* Note that we divert from the draft nomenclature and denominate * destination to what the draft refers to as origininator. So in this * function destnation refers to the final destination of the PREP, @@ -625,32 +628,32 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, len - baselen, &elems); - switch (mgmt->u.action.u.mesh_action.action_code) { - case MPATH_PREQ: - if (!elems.preq || elems.preq_len != 37) + mhwmp_dbg("RX path selection frame\n"); + if (elems.preq) { + if (elems.preq_len != 37) /* Right now we support just 1 destination and no AE */ return; - last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq); - if (!last_hop_metric) - return; - hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); - break; - case MPATH_PREP: - if (!elems.prep || elems.prep_len != 31) + last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, + MPATH_PREQ); + if (last_hop_metric) + hwmp_preq_frame_process(sdata, mgmt, elems.preq, + last_hop_metric); + } + if (elems.prep) { + if (elems.prep_len != 31) /* Right now we support no AE */ return; - last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep); - if (!last_hop_metric) - return; - hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric); - break; - case MPATH_PERR: - if (!elems.perr || elems.perr_len != 12) + last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, + MPATH_PREP); + if (last_hop_metric) + hwmp_prep_frame_process(sdata, mgmt, elems.prep, + last_hop_metric); + } + if (elems.perr) { + if (elems.perr_len != 12) /* Right now we support only one destination per PERR */ return; hwmp_perr_frame_process(sdata, mgmt, elems.perr); - default: - return; } } -- cgit v1.2.3 From f3c0d88a7fc1c3fff84ac57d3f3195d0dd1854ac Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:47 +0000 Subject: mac80211: improve HWMP debugging Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e67e812f78e..db1a33098a8 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -115,13 +115,13 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, switch (action) { case MPATH_PREQ: - mhwmp_dbg("sending PREQ\n"); + mhwmp_dbg("sending PREQ to %pM\n", dst); ie_len = 37; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREQ; break; case MPATH_PREP: - mhwmp_dbg("sending PREP\n"); + mhwmp_dbg("sending PREP to %pM\n", dst); ie_len = 31; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; @@ -439,7 +439,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); dst_flags = PREQ_IE_DST_F(preq_elem); - mhwmp_dbg("received PREQ\n"); + mhwmp_dbg("received PREQ from %pM\n", orig_addr); if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { mhwmp_dbg("PREQ is for us\n"); @@ -498,7 +498,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, ifmsh->mshstats.dropped_frames_ttl++; return; } - mhwmp_dbg("forwarding the PREQ\n"); + mhwmp_dbg("forwarding the PREQ from %pM\n", orig_addr); --ttl; flags = PREQ_IE_FLAGS(preq_elem); preq_id = PREQ_IE_PREQ_ID(preq_elem); @@ -525,7 +525,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, u8 next_hop[ETH_ALEN]; u32 dst_dsn, orig_dsn, lifetime; - mhwmp_dbg("received PREP\n"); + mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem)); /* Note that we divert from the draft nomenclature and denominate * destination to what the draft refers to as origininator. So in this @@ -628,7 +628,6 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, len - baselen, &elems); - mhwmp_dbg("RX path selection frame\n"); if (elems.preq) { if (elems.preq_len != 37) /* Right now we support just 1 destination and no AE */ -- cgit v1.2.3 From 1460dd158a520447b87661aea4afda1997d69cde Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:48 +0000 Subject: mac80211: improve peer link management debugging Print the FSM state strings instead of just the numbers. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8a54bc836c9..cf12f616c5b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -398,6 +398,17 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m u8 ie_len; u8 *baseaddr; __le16 plid, llid, reason; +#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG + static const char *mplstates[] = { + [PLINK_LISTEN] = "LISTEN", + [PLINK_OPN_SNT] = "OPN-SNT", + [PLINK_OPN_RCVD] = "OPN-RCVD", + [PLINK_CNF_RCVD] = "CNF_RCVD", + [PLINK_ESTAB] = "ESTAB", + [PLINK_HOLDING] = "HOLDING", + [PLINK_BLOCKED] = "BLOCKED" + }; +#endif /* need action_code, aux */ if (len < IEEE80211_MIN_ACTION_SIZE + 3) @@ -536,8 +547,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } } - mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %d %d %d %d\n", - mgmt->sa, sta->plink_state, + mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", + mgmt->sa, mplstates[sta->plink_state], le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), event); reason = 0; -- cgit v1.2.3 From 8b787643ca0a5130c647109d77fe512f89cfa611 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 10 Nov 2009 18:53:10 +0100 Subject: nl80211: add a parameter for using 4-address frames on virtual interfaces Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++++ include/net/cfg80211.h | 2 ++ net/wireless/nl80211.c | 11 +++++++++++ 3 files changed, 17 insertions(+) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 50afca3dcff..203adef972c 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -584,6 +584,8 @@ enum nl80211_commands { * changed then the list changed and the dump should be repeated * completely from scratch. * + * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -714,6 +716,8 @@ enum nl80211_attrs { NL80211_ATTR_PID, + NL80211_ATTR_4ADDR, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ff67865de23..1ee41e4a92e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -206,10 +206,12 @@ struct ieee80211_supported_band { * struct vif_params - describes virtual interface parameters * @mesh_id: mesh ID to use * @mesh_id_len: length of the mesh ID + * @use_4addr: use 4-address frames */ struct vif_params { u8 *mesh_id; int mesh_id_len; + int use_4addr; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8ed62b6c172..8c8e4eae6a1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -138,6 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, [NL80211_ATTR_PID] = { .type = NLA_U32 }, + [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, }; /* policy for the attributes */ @@ -987,6 +988,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) change = true; } + if (info->attrs[NL80211_ATTR_4ADDR]) { + params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); + change = true; + } else { + params.use_4addr = -1; + } + if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { if (ntype != NL80211_IFTYPE_MONITOR) { err = -EINVAL; @@ -1053,6 +1061,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); } + if (info->attrs[NL80211_ATTR_4ADDR]) + params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); -- cgit v1.2.3 From f14543ee4d0681df1377b976cba704557ba220d3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 10 Nov 2009 20:10:05 +0100 Subject: mac80211: implement support for 4-address frames for AP and client mode In some situations it might be useful to run a network with an Access Point and multiple clients, but with each client bridged to a network behind it. For this to work, both the client and the AP need to transmit 4-address frames, containing both source and destination MAC addresses. With this patch, you can configure a client to communicate using only 4-address frames for data traffic. On the AP side you can enable 4-address frames for individual clients by isolating them in separate AP VLANs which are configured in 4-address mode. Such an AP VLAN will be limited to one client only, and this client will be used as the destination for all traffic on its interface, regardless of the destination MAC address in the packet headers. The advantage of this mode compared to regular WDS mode is that it's easier to configure and does not require a static list of peer MAC addresses on any side. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 32 ++++++++++++++++++++++++++++++-- net/mac80211/ieee80211_i.h | 5 +++++ net/mac80211/iface.c | 4 ++++ net/mac80211/rx.c | 18 +++++++++++++++++- net/mac80211/sta_info.c | 3 +++ net/mac80211/tx.c | 45 +++++++++++++++++++++++++++++++++++++-------- net/wireless/util.c | 4 +++- 7 files changed, 99 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 56319b51d17..576b86f81d1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -36,6 +36,24 @@ static bool nl80211_type_check(enum nl80211_iftype type) } } +static bool nl80211_params_check(enum nl80211_iftype type, + struct vif_params *params) +{ + if (!nl80211_type_check(type)) + return false; + + if (params->use_4addr > 0) { + switch(type) { + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_STATION: + break; + default: + return false; + } + } + return true; +} + static int ieee80211_add_iface(struct wiphy *wiphy, char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params) @@ -45,7 +63,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, struct ieee80211_sub_if_data *sdata; int err; - if (!nl80211_type_check(type)) + if (!nl80211_params_check(type, params)) return -EINVAL; err = ieee80211_if_add(local, name, &dev, type, params); @@ -75,7 +93,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, if (netif_running(dev)) return -EBUSY; - if (!nl80211_type_check(type)) + if (!nl80211_params_check(type, params)) return -EINVAL; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -89,6 +107,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, params->mesh_id_len, params->mesh_id); + if (params->use_4addr >= 0) + sdata->use_4addr = !!params->use_4addr; + if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) return 0; @@ -806,6 +827,13 @@ static int ieee80211_change_station(struct wiphy *wiphy, return -EINVAL; } + if (vlansdata->use_4addr) { + if (vlansdata->u.vlan.sta) + return -EBUSY; + + rcu_assign_pointer(vlansdata->u.vlan.sta, sta); + } + sta->sdata = vlansdata; ieee80211_send_layer2_update(sta); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1f4f88a8f80..19b0c128d94 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -208,6 +208,9 @@ struct ieee80211_if_wds { struct ieee80211_if_vlan { struct list_head list; + + /* used for all tx if the VLAN is configured to 4-addr mode */ + struct sta_info *sta; }; struct mesh_stats { @@ -457,6 +460,8 @@ struct ieee80211_sub_if_data { int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ int max_ratectrl_rateidx; /* max TX rateidx for rate control */ + bool use_4addr; /* use 4-address frames */ + union { struct ieee80211_if_ap ap; struct ieee80211_if_wds wds; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8495161b99b..1f02b0610e8 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -752,6 +752,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, ieee80211_mandatory_rates(sdata->local, sdata->local->hw.conf.channel->band); sdata->drop_unencrypted = 0; + sdata->use_4addr = 0; return 0; } @@ -819,6 +820,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, params->mesh_id_len, params->mesh_id); + if (params && params->use_4addr >= 0) + sdata->use_4addr = !!params->use_4addr; + mutex_lock(&local->iflist_mtx); list_add_tail_rcu(&sdata->list, &local->interfaces); mutex_unlock(&local->iflist_mtx); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4066570dd41..76478362a53 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1181,6 +1181,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr && + ieee80211_has_a4(hdr->frame_control)) + return -1; + if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1)) + return -1; return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); } @@ -1534,6 +1541,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); __le16 fc = hdr->frame_control; int err; @@ -1543,6 +1551,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) return RX_DROP_MONITOR; + /* + * Allow the cooked monitor interface of an AP to see 4-addr frames so + * that a 4-addr station can be detected and moved into a separate VLAN + */ + if (ieee80211_has_a4(hdr->frame_control) && + sdata->vif.type == NL80211_IFTYPE_AP) + return RX_DROP_MONITOR; + err = __ieee80211_data_to_8023(rx); if (unlikely(err)) return RX_DROP_UNUSABLE; @@ -1983,7 +1999,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: - if (!bssid) + if (!bssid && !sdata->use_4addr) return 0; if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index be59456e8a4..396a94806de 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -509,6 +509,9 @@ static void __sta_info_unlink(struct sta_info **sta) local->num_sta--; local->sta_generation++; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + rcu_assign_pointer(sdata->u.vlan.sta, NULL); + if (local->ops->sta_notify) { if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bfaa43e096d..2f3345c5f7c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1051,7 +1051,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, hdr = (struct ieee80211_hdr *) skb->data; - tx->sta = sta_info_get(local, hdr->addr1); + if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr) + tx->sta = rcu_dereference(sdata->u.vlan.sta); + if (!tx->sta) + tx->sta = sta_info_get(local, hdr->addr1); if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { @@ -1613,7 +1616,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, const u8 *encaps_data; int encaps_len, skip_header_bytes; int nh_pos, h_pos; - struct sta_info *sta; + struct sta_info *sta = NULL; u32 sta_flags = 0; if (unlikely(skb->len < ETH_HLEN)) { @@ -1630,8 +1633,25 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: + rcu_read_lock(); + if (sdata->use_4addr) + sta = rcu_dereference(sdata->u.vlan.sta); + if (sta) { + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + /* RA TA DA SA */ + memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 30; + sta_flags = get_sta_flags(sta); + } + rcu_read_unlock(); + if (sta) + break; + /* fall through */ + case NL80211_IFTYPE_AP: fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); @@ -1705,12 +1725,21 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, break; #endif case NL80211_IFTYPE_STATION: - fc |= cpu_to_le16(IEEE80211_FCTL_TODS); - /* BSSID SA DA */ memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); - memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); - memcpy(hdr.addr3, skb->data, ETH_ALEN); - hdrlen = 24; + if (sdata->use_4addr && ethertype != ETH_P_PAE) { + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + /* RA TA DA SA */ + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 30; + } else { + fc |= cpu_to_le16(IEEE80211_FCTL_TODS); + /* BSSID SA DA */ + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + hdrlen = 24; + } break; case NL80211_IFTYPE_ADHOC: /* DA SA BSSID */ diff --git a/net/wireless/util.c b/net/wireless/util.c index 3fc2df86278..5aa39f7cf9b 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, break; case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): if (unlikely(iftype != NL80211_IFTYPE_WDS && - iftype != NL80211_IFTYPE_MESH_POINT)) + iftype != NL80211_IFTYPE_MESH_POINT && + iftype != NL80211_IFTYPE_AP_VLAN && + iftype != NL80211_IFTYPE_STATION)) return -1; if (iftype == NL80211_IFTYPE_MESH_POINT) { struct ieee80211s_hdr *meshdr = -- cgit v1.2.3 From e5d6eb8305a4c116fc94ce28b8136c538c92442f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 9 Nov 2009 16:03:22 -0500 Subject: mac80211: fix max HT rate processing on mac80211 The max MCS index is 76, fix the higher check to allow through frames received at MCS 76. This is a non-issue for current drivers as MCS 76 is only possible with a device supporting 4 spatial streams. While at it change the WARN_ON() on invalid HT rates to a WARN() to provide more useful information. This will help debug issues when the driver is passing up a bogus HT rate value. The rate must map to a valid MCS index which can be any of the values in the set [0 - 76] (inclusive). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/rx.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 76478362a53..006cf89df70 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2441,9 +2441,21 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) goto drop; if (status->flag & RX_FLAG_HT) { - /* rate_idx is MCS index */ - if (WARN_ON(status->rate_idx < 0 || - status->rate_idx >= 76)) + /* + * rate_idx is MCS index, which can be [0-76] as documented on: + * + * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n + * + * Anything else would be some sort of driver or hardware error. + * The driver should catch hardware errors. + */ + if (WARN((status->rate_idx < 0 || + status->rate_idx > 76), + "Rate marked as an HT rate but passed " + "status->rate_idx is not " + "an MCS index [0-76]: %d (0x%02x)\n", + status->rate_idx, + status->rate_idx)) goto drop; /* HT rates are not in the table - use the highest legacy rate * for now since other parts of mac80211 may not yet be fully -- cgit v1.2.3 From 434a8a58d75faa7170807a7ac2fcf7f3d85a0dc3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 11 Nov 2009 18:53:00 -0800 Subject: ipv6: Remove unused var in inet6_dump_ifinfo() Reported by Stephen Rothwell: -------------------- Today's linux-next build (x86_64 allmodconfig) produced this warning: net/ipv6/addrconf.c: In function 'inet6_dump_ifinfo': net/ipv6/addrconf.c:3833: warning: unused variable 'err' Introduced by commit 84d2697d9649339215675551eae28ba04068dea1 ("ipv6: speedup inet6_dump_ifinfo()"). -------------------- Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0ab39fedd2d..9ff8ab9a154 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3830,7 +3830,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); int h, s_h; - int idx = 0, err, s_idx; + int idx = 0, s_idx; struct net_device *dev; struct inet6_dev *idev; struct hlist_head *head; -- cgit v1.2.3 From e84af6ddef0e447c56b256a2bb5a90af11bdac2e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 10 Nov 2009 14:11:01 +0000 Subject: skbuff: Do not allow skb recycling with disabled IRQs NAPI drivers try to recycle SKBs in their polling routine, but we generally don't know the context in which the polling will be called, and the skb recycling itself may require IRQs to be enabled. This patch adds irqs_disabled() test to the skb_recycle_check() routine, so that we'll not let the drivers hit the skb recycling path with IRQs disabled. As a side effect, this patch actually disables skb recycling for some [broken] drivers. E.g. gianfar driver grabs an irqsave spinlock during TX ring processing, and then tries to recycle an skb, and that caused the following badness: nf_conntrack version 0.5.0 (1008 buckets, 4032 max) ------------[ cut here ]------------ Badness at kernel/softirq.c:143 NIP: c003e3c4 LR: c423a528 CTR: c003e344 ... NIP [c003e3c4] local_bh_enable+0x80/0xc4 LR [c423a528] destroy_conntrack+0xd4/0x13c [nf_conntrack] Call Trace: [c15d1b60] [c003e32c] local_bh_disable+0x1c/0x34 (unreliable) [c15d1b70] [c423a528] destroy_conntrack+0xd4/0x13c [nf_conntrack] [c15d1b80] [c02c6370] nf_conntrack_destroy+0x3c/0x70 Signed-off-by: David S. Miller --- net/core/skbuff.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 80a96166df3..941bac90748 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -493,6 +493,9 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size) { struct skb_shared_info *shinfo; + if (irqs_disabled()) + return 0; + if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE) return 0; -- cgit v1.2.3 From 08e9897d512fe7a67e46209543b3815b57a36dc7 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 10 Nov 2009 07:20:34 +0000 Subject: netdev: fold name hash properly (v3) The full_name_hash function does not produce well distributed values in the lower bits, so most code uses hash_32() to fold it. This is really a bug introduced when name hashing was added, back in 2.5 when I added name hashing. hash_32 is all that is needed since full_name_hash returns unsigned int which is only 32 bits on 64 bit platforms. Also, there is no point in using hash_32 on ifindex, because the is naturally sequential and usually well distributed. Signed-off-by: Stephen Hemminger Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index bf629ac08b8..ad8e320ceba 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -196,7 +197,7 @@ EXPORT_SYMBOL(dev_base_lock); static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) { unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); - return &net->dev_name_head[hash & (NETDEV_HASHENTRIES - 1)]; + return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)]; } static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) -- cgit v1.2.3 From 41bdecf17e6dba92256c65972ec79a482d978be5 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 11 Nov 2009 07:39:27 +0000 Subject: decnet: add RTNL lock when reading address list Add missing locking in the case of auto binding to the default device. The address list might change while this code is looking at the list. Compile tested only, I am not a decnet user. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/decnet/dn_dev.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index b5ef237c8a7..5790d660bc7 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -828,13 +828,17 @@ static int dn_dev_get_first(struct net_device *dev, __le16 *addr) struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; struct dn_ifaddr *ifa; int rv = -ENODEV; + if (dn_db == NULL) goto out; + + rtnl_lock(); ifa = dn_db->ifa_list; if (ifa != NULL) { *addr = ifa->ifa_local; rv = 0; } + rtnl_unlock(); out: return rv; } -- cgit v1.2.3 From e5c140a340c4796054b0f6e9035e1faa7edfa6d6 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 11 Nov 2009 07:40:36 +0000 Subject: decnet: convert dndev_lock to spinlock There is no reason for this lock to be reader/writer since the reader only has lock held for a very brief period. The overhead of read_lock is more expensive than spinlock. Compile tested only, I am not a decnet user. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/decnet/dn_dev.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 5790d660bc7..6c916e2b8a8 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -68,7 +68,7 @@ extern struct neigh_table dn_neigh_table; */ __le16 decnet_address = 0; -static DEFINE_RWLOCK(dndev_lock); +static DEFINE_SPINLOCK(dndev_lock); static struct net_device *decnet_default_device; static BLOCKING_NOTIFIER_HEAD(dnaddr_chain); @@ -557,7 +557,8 @@ rarok: struct net_device *dn_dev_get_default(void) { struct net_device *dev; - read_lock(&dndev_lock); + + spin_lock(&dndev_lock); dev = decnet_default_device; if (dev) { if (dev->dn_ptr) @@ -565,7 +566,8 @@ struct net_device *dn_dev_get_default(void) else dev = NULL; } - read_unlock(&dndev_lock); + spin_unlock(&dndev_lock); + return dev; } @@ -575,13 +577,15 @@ int dn_dev_set_default(struct net_device *dev, int force) int rv = -EBUSY; if (!dev->dn_ptr) return -ENODEV; - write_lock(&dndev_lock); + + spin_lock(&dndev_lock); if (force || decnet_default_device == NULL) { old = decnet_default_device; decnet_default_device = dev; rv = 0; } - write_unlock(&dndev_lock); + spin_unlock(&dndev_lock); + if (old) dev_put(old); return rv; @@ -589,13 +593,14 @@ int dn_dev_set_default(struct net_device *dev, int force) static void dn_dev_check_default(struct net_device *dev) { - write_lock(&dndev_lock); + spin_lock(&dndev_lock); if (dev == decnet_default_device) { decnet_default_device = NULL; } else { dev = NULL; } - write_unlock(&dndev_lock); + spin_unlock(&dndev_lock); + if (dev) dev_put(dev); } -- cgit v1.2.3 From a2116ed223c88b6c424f42398e54d1607dc785ba Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Nov 2009 03:39:40 +0000 Subject: net/compat: fix dev_ifsioc emulation corner cases Handling for SIOCSHWTSTAMP is broken on architectures with a split user/kernel address space like s390, because it passes a real user pointer while using set_fs(KERNEL_DS). A similar problem might arise the next time somebody adds code to dev_ifsioc. Split up dev_ifsioc into three separate functions for SIOCSHWTSTAMP, SIOC*IFMAP and all other numbers so we can get rid of set_fs in all potentially affected cases. Signed-off-by: Arnd Bergmann Cc: Patrick Ohly Cc: David S. Miller Signed-off-by: David S. Miller --- net/socket.c | 117 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 45 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index befd9f5b162..05c482848a6 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2723,38 +2723,15 @@ static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, static int dev_ifsioc(struct net *net, struct socket *sock, unsigned int cmd, struct compat_ifreq __user *uifr32) { - struct ifreq ifr; - struct compat_ifmap __user *uifmap32; - mm_segment_t old_fs; + struct ifreq __user *uifr; int err; - uifmap32 = &uifr32->ifr_ifru.ifru_map; - switch (cmd) { - case SIOCSIFMAP: - err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); - err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); - err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); - err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); - err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq); - err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma); - err |= __get_user(ifr.ifr_map.port, &uifmap32->port); - if (err) - return -EFAULT; - break; - case SIOCSHWTSTAMP: - if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) - return -EFAULT; - ifr.ifr_data = compat_ptr(uifr32->ifr_ifru.ifru_data); - break; - default: - if (copy_from_user(&ifr, uifr32, sizeof(*uifr32))) - return -EFAULT; - break; - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ifr); - set_fs (old_fs); + uifr = compat_alloc_user_space(sizeof(*uifr)); + if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) + return -EFAULT; + + err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); + if (!err) { switch (cmd) { case SIOCGIFFLAGS: @@ -2771,18 +2748,7 @@ static int dev_ifsioc(struct net *net, struct socket *sock, case SIOCGIFTXQLEN: case SIOCGMIIPHY: case SIOCGMIIREG: - if (copy_to_user(uifr32, &ifr, sizeof(*uifr32))) - return -EFAULT; - break; - case SIOCGIFMAP: - err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); - err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); - err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); - err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); - err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq); - err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma); - err |= __put_user(ifr.ifr_map.port, &uifmap32->port); - if (err) + if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) err = -EFAULT; break; } @@ -2790,6 +2756,65 @@ static int dev_ifsioc(struct net *net, struct socket *sock, return err; } +static int compat_sioc_ifmap(struct net *net, unsigned int cmd, + struct compat_ifreq __user *uifr32) +{ + struct ifreq ifr; + struct compat_ifmap __user *uifmap32; + mm_segment_t old_fs; + int err; + + uifmap32 = &uifr32->ifr_ifru.ifru_map; + err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); + err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); + err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); + err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); + err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq); + err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma); + err |= __get_user(ifr.ifr_map.port, &uifmap32->port); + if (err) + return -EFAULT; + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = dev_ioctl(net, cmd, (void __user *)&ifr); + set_fs (old_fs); + + if (cmd == SIOCGIFMAP && !err) { + err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); + err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); + err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); + err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); + err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq); + err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma); + err |= __put_user(ifr.ifr_map.port, &uifmap32->port); + if (err) + err = -EFAULT; + } + return err; +} + +static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) +{ + void __user *uptr; + compat_uptr_t uptr32; + struct ifreq __user *uifr; + + uifr = compat_alloc_user_space(sizeof (*uifr)); + if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) + return -EFAULT; + + if (get_user(uptr32, &uifr32->ifr_data)) + return -EFAULT; + + uptr = compat_ptr(uptr32); + + if (put_user(uptr, &uifr->ifr_data)) + return -EFAULT; + + return dev_ioctl(net, SIOCSHWTSTAMP, uifr); +} + struct rtentry32 { u32 rt_pad1; struct sockaddr rt_dst; /* target address */ @@ -3081,6 +3106,9 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, return ethtool_ioctl(net, argp); case SIOCWANDEV: return compat_siocwandev(net, argp); + case SIOCGIFMAP: + case SIOCSIFMAP: + return compat_sioc_ifmap(net, cmd, argp); case SIOCBONDENSLAVE: case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: @@ -3095,6 +3123,8 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, return do_siocgstamp(net, sock, cmd, argp); case SIOCGSTAMPNS: return do_siocgstampns(net, sock, cmd, argp); + case SIOCSHWTSTAMP: + return compat_siocshwtstamp(net, argp); case FIOSETOWN: case SIOCSPGRP: @@ -3121,12 +3151,9 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCADDMULTI: case SIOCDELMULTI: case SIOCGIFINDEX: - case SIOCGIFMAP: - case SIOCSIFMAP: case SIOCGIFADDR: case SIOCSIFADDR: case SIOCSIFHWBROADCAST: - case SIOCSHWTSTAMP: case SIOCDIFADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: -- cgit v1.2.3 From 805003a41c035ccbe37d3d5ef5e6df8874346b5a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Nov 2009 03:45:22 +0000 Subject: net/atm: move all compat_ioctl handling to atm/ioctl.c We have two implementations of the compat_ioctl handling for ATM, the one that we have had for ages in fs/compat_ioctl.c and the one added to net/atm/ioctl.c by David Woodhouse. Unfortunately, both versions are incomplete, and in practice we use a very confusing combination of the two. For ioctl numbers that have the same identifier on 32 and 64 bit systems, we go directly through the compat_ioctl socket operation, for those that differ, we do a conversion in fs/compat_ioctl.c. This patch moves both variants into the vcc_compat_ioctl() function, while preserving the current behaviour. It also kills off the COMPATIBLE_IOCTL definitions that we never use here. Doing it this way is clearly not a good solution, but I hope it is a step into the right direction, so that someone is able to clean up this mess for real. Signed-off-by: Arnd Bergmann Cc: Eric Dumazet Cc: David Woodhouse Signed-off-by: David S. Miller --- net/atm/ioctl.c | 177 ++++++++++++++++++++++++++++++++++++++++++++- net/socket.c | 218 -------------------------------------------------------- 2 files changed, 175 insertions(+), 220 deletions(-) (limited to 'net') diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index 4da8892ced5..2ea40995dce 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -191,8 +191,181 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT -int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +/* + * FIXME: + * The compat_ioctl handling is duplicated, using both these conversion + * routines and the compat argument to the actual handlers. Both + * versions are somewhat incomplete and should be merged, e.g. by + * moving the ioctl number translation into the actual handlers and + * killing the conversion code. + * + * -arnd, November 2009 + */ +#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct compat_atmif_sioc) +#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct compat_atm_iobuf) +#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct compat_atmif_sioc) +#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct compat_atmif_sioc) +#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct compat_atmif_sioc) +#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct compat_atmif_sioc) +#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct compat_atmif_sioc) +#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct compat_atmif_sioc) +#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct compat_atmif_sioc) +#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct compat_atmif_sioc) +#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct compat_atmif_sioc) +#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct compat_atmif_sioc) +#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct compat_atmif_sioc) +#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct compat_atmif_sioc) +#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct compat_atmif_sioc) +#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct compat_atmif_sioc) +#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct compat_atmif_sioc) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} atm_ioctl_map[] = { + { ATM_GETLINKRATE32, ATM_GETLINKRATE }, + { ATM_GETNAMES32, ATM_GETNAMES }, + { ATM_GETTYPE32, ATM_GETTYPE }, + { ATM_GETESI32, ATM_GETESI }, + { ATM_GETADDR32, ATM_GETADDR }, + { ATM_RSTADDR32, ATM_RSTADDR }, + { ATM_ADDADDR32, ATM_ADDADDR }, + { ATM_DELADDR32, ATM_DELADDR }, + { ATM_GETCIRANGE32, ATM_GETCIRANGE }, + { ATM_SETCIRANGE32, ATM_SETCIRANGE }, + { ATM_SETESI32, ATM_SETESI }, + { ATM_SETESIF32, ATM_SETESIF }, + { ATM_GETSTAT32, ATM_GETSTAT }, + { ATM_GETSTATZ32, ATM_GETSTATZ }, + { ATM_GETLOOP32, ATM_GETLOOP }, + { ATM_SETLOOP32, ATM_SETLOOP }, + { ATM_QUERYLOOP32, ATM_QUERYLOOP }, +}; + +#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map) + +static int do_atm_iobuf(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + struct atm_iobuf __user *iobuf; + struct compat_atm_iobuf __user *iobuf32; + u32 data; + void __user *datap; + int len, err; + + iobuf = compat_alloc_user_space(sizeof(*iobuf)); + iobuf32 = compat_ptr(arg); + + if (get_user(len, &iobuf32->length) || + get_user(data, &iobuf32->buffer)) + return -EFAULT; + datap = compat_ptr(data); + if (put_user(len, &iobuf->length) || + put_user(datap, &iobuf->buffer)) + return -EFAULT; + + err = do_vcc_ioctl(sock, cmd, (unsigned long) iobuf, 0); + + if (!err) { + if (copy_in_user(&iobuf32->length, &iobuf->length, + sizeof(int))) + err = -EFAULT; + } + + return err; +} + +static int do_atmif_sioc(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + struct atmif_sioc __user *sioc; + struct compat_atmif_sioc __user *sioc32; + u32 data; + void __user *datap; + int err; + + sioc = compat_alloc_user_space(sizeof(*sioc)); + sioc32 = compat_ptr(arg); + + if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) + || get_user(data, &sioc32->arg)) + return -EFAULT; + datap = compat_ptr(data); + if (put_user(datap, &sioc->arg)) + return -EFAULT; + + err = do_vcc_ioctl(sock, cmd, (unsigned long) sioc, 0); + + if (!err) { + if (copy_in_user(&sioc32->length, &sioc->length, + sizeof(int))) + err = -EFAULT; + } + return err; +} + +static int do_atm_ioctl(struct socket *sock, unsigned int cmd32, + unsigned long arg) +{ + int i; + unsigned int cmd = 0; + + switch (cmd32) { + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: + return do_atmif_sioc(sock, cmd32, arg); + } + + for (i = 0; i < NR_ATM_IOCTL; i++) { + if (cmd32 == atm_ioctl_map[i].cmd32) { + cmd = atm_ioctl_map[i].cmd; + break; + } + } + if (i == NR_ATM_IOCTL) + return -EINVAL; + + switch (cmd) { + case ATM_GETNAMES: + return do_atm_iobuf(sock, cmd, arg); + + case ATM_GETLINKRATE: + case ATM_GETTYPE: + case ATM_GETESI: + case ATM_GETADDR: + case ATM_RSTADDR: + case ATM_ADDADDR: + case ATM_DELADDR: + case ATM_GETCIRANGE: + case ATM_SETCIRANGE: + case ATM_SETESI: + case ATM_SETESIF: + case ATM_GETSTAT: + case ATM_GETSTATZ: + case ATM_GETLOOP: + case ATM_SETLOOP: + case ATM_QUERYLOOP: + return do_atmif_sioc(sock, cmd, arg); + } + + return -EINVAL; +} + +int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) { - return do_vcc_ioctl(sock, cmd, arg, 1); + int ret; + + ret = do_vcc_ioctl(sock, cmd, arg, 1); + if (ret != -ENOIOCTLCMD) + return ret; + + return do_atm_ioctl(sock, cmd, arg); } #endif diff --git a/net/socket.c b/net/socket.c index 05c482848a6..402abb39cbf 100644 --- a/net/socket.c +++ b/net/socket.c @@ -100,14 +100,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -2917,173 +2909,6 @@ static int old_bridge_ioctl(compat_ulong_t __user *argp) return -EINVAL; } -struct atmif_sioc32 { - compat_int_t number; - compat_int_t length; - compat_caddr_t arg; -}; - -struct atm_iobuf32 { - compat_int_t length; - compat_caddr_t buffer; -}; - -#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) -#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) -#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) -#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) -#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) -#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) -#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) -#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) -#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) -#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) -#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) -#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) -#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) -#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) -#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) -#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) -#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} atm_ioctl_map[] = { - { ATM_GETLINKRATE32, ATM_GETLINKRATE }, - { ATM_GETNAMES32, ATM_GETNAMES }, - { ATM_GETTYPE32, ATM_GETTYPE }, - { ATM_GETESI32, ATM_GETESI }, - { ATM_GETADDR32, ATM_GETADDR }, - { ATM_RSTADDR32, ATM_RSTADDR }, - { ATM_ADDADDR32, ATM_ADDADDR }, - { ATM_DELADDR32, ATM_DELADDR }, - { ATM_GETCIRANGE32, ATM_GETCIRANGE }, - { ATM_SETCIRANGE32, ATM_SETCIRANGE }, - { ATM_SETESI32, ATM_SETESI }, - { ATM_SETESIF32, ATM_SETESIF }, - { ATM_GETSTAT32, ATM_GETSTAT }, - { ATM_GETSTATZ32, ATM_GETSTATZ }, - { ATM_GETLOOP32, ATM_GETLOOP }, - { ATM_SETLOOP32, ATM_SETLOOP }, - { ATM_QUERYLOOP32, ATM_QUERYLOOP } -}; - -#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map) - -static int do_atm_iobuf(struct net *net, struct socket *sock, - unsigned int cmd, unsigned long arg) -{ - struct atm_iobuf __user *iobuf; - struct atm_iobuf32 __user *iobuf32; - u32 data; - void __user *datap; - int len, err; - - iobuf = compat_alloc_user_space(sizeof(*iobuf)); - iobuf32 = compat_ptr(arg); - - if (get_user(len, &iobuf32->length) || - get_user(data, &iobuf32->buffer)) - return -EFAULT; - datap = compat_ptr(data); - if (put_user(len, &iobuf->length) || - put_user(datap, &iobuf->buffer)) - return -EFAULT; - - err = sock_do_ioctl(net, sock, cmd, (unsigned long)iobuf); - - if (!err) { - if (copy_in_user(&iobuf32->length, &iobuf->length, - sizeof(int))) - err = -EFAULT; - } - - return err; -} - -static int do_atmif_sioc(struct net *net, struct socket *sock, - unsigned int cmd, unsigned long arg) -{ - struct atmif_sioc __user *sioc; - struct atmif_sioc32 __user *sioc32; - u32 data; - void __user *datap; - int err; - - sioc = compat_alloc_user_space(sizeof(*sioc)); - sioc32 = compat_ptr(arg); - - if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) || - get_user(data, &sioc32->arg)) - return -EFAULT; - datap = compat_ptr(data); - if (put_user(datap, &sioc->arg)) - return -EFAULT; - - err = sock_do_ioctl(net, sock, cmd, (unsigned long) sioc); - - if (!err) { - if (copy_in_user(&sioc32->length, &sioc->length, - sizeof(int))) - err = -EFAULT; - } - return err; -} - -static int do_atm_ioctl(struct net *net, struct socket *sock, - unsigned int cmd32, unsigned long arg) -{ - int i; - unsigned int cmd = 0; - - switch (cmd32) { - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_GETDIAG: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: - return do_atmif_sioc(net, sock, cmd32, arg); - } - - for (i = 0; i < NR_ATM_IOCTL; i++) { - if (cmd32 == atm_ioctl_map[i].cmd32) { - cmd = atm_ioctl_map[i].cmd; - break; - } - } - if (i == NR_ATM_IOCTL) - return -EINVAL; - - switch (cmd) { - case ATM_GETNAMES: - return do_atm_iobuf(net, sock, cmd, arg); - - case ATM_GETLINKRATE: - case ATM_GETTYPE: - case ATM_GETESI: - case ATM_GETADDR: - case ATM_RSTADDR: - case ATM_ADDADDR: - case ATM_DELADDR: - case ATM_GETCIRANGE: - case ATM_SETCIRANGE: - case ATM_SETESI: - case ATM_SETESIF: - case ATM_GETSTAT: - case ATM_GETSTATZ: - case ATM_GETLOOP: - case ATM_SETLOOP: - case ATM_QUERYLOOP: - return do_atmif_sioc(net, sock, cmd, arg); - } - - return -EINVAL; -} - static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, unsigned int cmd, unsigned long arg) { @@ -3173,49 +2998,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCSMIIREG: return dev_ifsioc(net, sock, cmd, argp); - case ATM_GETLINKRATE32: - case ATM_GETNAMES32: - case ATM_GETTYPE32: - case ATM_GETESI32: - case ATM_GETADDR32: - case ATM_RSTADDR32: - case ATM_ADDADDR32: - case ATM_DELADDR32: - case ATM_GETCIRANGE32: - case ATM_SETCIRANGE32: - case ATM_SETESI32: - case ATM_SETESIF32: - case ATM_GETSTAT32: - case ATM_GETSTATZ32: - case ATM_GETLOOP32: - case ATM_SETLOOP32: - case ATM_QUERYLOOP32: - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_GETDIAG: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: - return do_atm_ioctl(net, sock, cmd, arg); - - case ATMSIGD_CTRL: - case ATMARPD_CTRL: - case ATMLEC_CTRL: - case ATMLEC_MCAST: - case ATMLEC_DATA: - case ATM_SETSC: - case SIOCSIFATMTCP: - case SIOCMKCLIP: - case ATMARP_MKIP: - case ATMARP_SETENTRY: - case ATMARP_ENCAP: - case ATMTCP_CREATE: - case ATMTCP_REMOVE: - case ATMMPC_CTRL: - case ATMMPC_DATA: - case SIOCSARP: case SIOCGARP: case SIOCDARP: -- cgit v1.2.3 From 282a39546f6d213399b325ec830ee37e8d915924 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 12 Nov 2009 23:58:23 +0300 Subject: ieee802154: make wpan-phy class registration to subsys_initcall Move ieee802154 initialisation to subsys_initcall call, so that wpan-phy class is initialised before all devices (thus saving us from oops during bootup). Signed-off-by: Dmitry Eremin-Solenikov --- net/ieee802154/wpan-class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 38bac70cca1..268691256a6 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -205,7 +205,7 @@ err_nl: err: return rc; } -module_init(wpan_phy_class_init); +subsys_initcall(wpan_phy_class_init); static void __exit wpan_phy_class_exit(void) { -- cgit v1.2.3 From 572a9d7b6fc7f20f573664063324c086be310c42 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 10 Nov 2009 06:14:14 +0000 Subject: net: allow to propagate errors through ->ndo_hard_start_xmit() Currently the ->ndo_hard_start_xmit() callbacks are only permitted to return one of the NETDEV_TX codes. This prevents any kind of error propagation for virtual devices, like queue congestion of the underlying device in case of layered devices, or unreachability in case of tunnels. This patches changes the NET_XMIT codes to avoid clashes with the NETDEV_TX codes and changes the two callers of dev_hard_start_xmit() to expect either errno codes, NET_XMIT codes or NETDEV_TX codes as return value. In case of qdisc_restart(), all non NETDEV_TX codes are mapped to NETDEV_TX_OK since no error propagation is possible when using qdiscs. In case of dev_queue_xmit(), the error is propagated upwards. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netdevice.h | 43 ++++++++++++++++++++++++++++++++----------- net/core/dev.c | 32 ++++++++++++++++++++++++++------ net/sched/sch_generic.c | 9 ++++++++- 3 files changed, 66 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 083b5989cec..8b266390b9e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -63,27 +63,48 @@ struct wireless_dev; #define HAVE_FREE_NETDEV /* free_netdev() */ #define HAVE_NETDEV_PRIV /* netdev_priv() */ -#define NET_XMIT_SUCCESS 0 -#define NET_XMIT_DROP 1 /* skb dropped */ -#define NET_XMIT_CN 2 /* congestion notification */ -#define NET_XMIT_POLICED 3 /* skb is shot by police */ -#define NET_XMIT_MASK 0xFFFF /* qdisc flags in net/sch_generic.h */ +/* + * Transmit return codes: transmit return codes originate from three different + * namespaces: + * + * - qdisc return codes + * - driver transmit return codes + * - errno values + * + * Drivers are allowed to return any one of those in their hard_start_xmit() + * function. Real network devices commonly used with qdiscs should only return + * the driver transmit return codes though - when qdiscs are used, the actual + * transmission happens asynchronously, so the value is not propagated to + * higher layers. Virtual network devices transmit synchronously, in this case + * the driver transmit return codes are consumed by dev_queue_xmit(), all + * others are propagated to higher layers. + */ + +/* qdisc ->enqueue() return codes. */ +#define NET_XMIT_SUCCESS 0x00 +#define NET_XMIT_DROP 0x10 /* skb dropped */ +#define NET_XMIT_CN 0x20 /* congestion notification */ +#define NET_XMIT_POLICED 0x30 /* skb is shot by police */ +#define NET_XMIT_MASK 0xf0 /* qdisc flags in net/sch_generic.h */ /* Backlog congestion levels */ -#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ -#define NET_RX_DROP 1 /* packet dropped */ +#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ +#define NET_RX_DROP 1 /* packet dropped */ /* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It * indicates that the device will soon be dropping packets, or already drops * some packets of the same priority; prompting us to send less aggressively. */ -#define net_xmit_eval(e) ((e) == NET_XMIT_CN? 0 : (e)) +#define net_xmit_eval(e) ((e) == NET_XMIT_CN ? 0 : (e)) #define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) /* Driver transmit return codes */ +#define NETDEV_TX_MASK 0xf + enum netdev_tx { - NETDEV_TX_OK = 0, /* driver took care of packet */ - NETDEV_TX_BUSY, /* driver tx path was busy*/ - NETDEV_TX_LOCKED = -1, /* driver tx lock was already taken */ + __NETDEV_TX_MIN = INT_MIN, /* make sure enum is signed */ + NETDEV_TX_OK = 0, /* driver took care of packet */ + NETDEV_TX_BUSY = 1, /* driver tx path was busy*/ + NETDEV_TX_LOCKED = 2, /* driver tx lock was already taken */ }; typedef enum netdev_tx netdev_tx_t; diff --git a/net/core/dev.c b/net/core/dev.c index ad8e320ceba..548340b5729 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1757,7 +1757,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq) { const struct net_device_ops *ops = dev->netdev_ops; - int rc; + int rc = NETDEV_TX_OK; if (likely(!skb->next)) { if (!list_empty(&ptype_all)) @@ -1805,6 +1805,8 @@ gso: nskb->next = NULL; rc = ops->ndo_start_xmit(nskb, dev); if (unlikely(rc != NETDEV_TX_OK)) { + if (rc & ~NETDEV_TX_MASK) + goto out_kfree_gso_skb; nskb->next = skb->next; skb->next = nskb; return rc; @@ -1814,11 +1816,12 @@ gso: return NETDEV_TX_BUSY; } while (skb->next); - skb->destructor = DEV_GSO_CB(skb)->destructor; - +out_kfree_gso_skb: + if (likely(skb->next == NULL)) + skb->destructor = DEV_GSO_CB(skb)->destructor; out_kfree_skb: kfree_skb(skb); - return NETDEV_TX_OK; + return rc; } static u32 skb_tx_hashrnd; @@ -1906,6 +1909,23 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, return rc; } +static inline bool dev_xmit_complete(int rc) +{ + /* successful transmission */ + if (rc == NETDEV_TX_OK) + return true; + + /* error while transmitting, driver consumed skb */ + if (rc < 0) + return true; + + /* error while queueing to a different device, driver consumed skb */ + if (rc & NET_XMIT_MASK) + return true; + + return false; +} + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -2003,8 +2023,8 @@ gso: HARD_TX_LOCK(dev, txq, cpu); if (!netif_tx_queue_stopped(txq)) { - rc = NET_XMIT_SUCCESS; - if (!dev_hard_start_xmit(skb, dev, txq)) { + rc = dev_hard_start_xmit(skb, dev, txq); + if (dev_xmit_complete(rc)) { HARD_TX_UNLOCK(dev, txq); goto out; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 4ae6aa562f2..b13821ad2fb 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -120,8 +120,15 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, HARD_TX_LOCK(dev, txq, smp_processor_id()); if (!netif_tx_queue_stopped(txq) && - !netif_tx_queue_frozen(txq)) + !netif_tx_queue_frozen(txq)) { ret = dev_hard_start_xmit(skb, dev, txq); + + /* an error implies that the skb was consumed */ + if (ret < 0) + ret = NETDEV_TX_OK; + /* all NET_XMIT codes map to NETDEV_TX_OK */ + ret &= ~NET_XMIT_MASK; + } HARD_TX_UNLOCK(dev, txq); spin_lock(root_lock); -- cgit v1.2.3 From cbbef5e183079455763fc470ccf69008f92ab4b6 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 10 Nov 2009 06:14:24 +0000 Subject: vlan/macvlan: propagate transmission state to upper layers Both vlan and macvlan devices usually don't use a qdisc and immediately queue packets to the underlying device. Propagate transmission state of the underlying device to the upper layers so they can react on congestion and/or inform the sending process. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 2 +- net/8021q/vlan_dev.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d7dba3f6f76..271aa7e1d03 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -202,7 +202,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, } else txq->tx_dropped++; - return NETDEV_TX_OK; + return ret; } static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 790fd55ec31..91596594213 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -332,7 +332,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, } else txq->tx_dropped++; - return NETDEV_TX_OK; + return ret; } static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, @@ -358,7 +358,7 @@ static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, } else txq->tx_dropped++; - return NETDEV_TX_OK; + return ret; } static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) -- cgit v1.2.3 From 90a5e16992fa6105f7ebf3f29f5cf5feb1bbf7dc Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Wed, 11 Nov 2009 00:01:31 +0000 Subject: mac80211: implement RANN processing and forwarding Process the RANN (Root Annoucement) Frame and try to find the HWMP root station by sending a PREQ. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 15 +++++++++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/mesh_hwmp.c | 79 +++++++++++++++++++++++++++++++++++++++++----- net/mac80211/util.c | 4 +++ 4 files changed, 91 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 50c684db33c..49b1abd2fe9 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -554,6 +554,20 @@ struct ieee80211_tim_ie { u8 virtual_map[1]; } __attribute__ ((packed)); +/** + * struct ieee80211_rann_ie + * + * This structure refers to "Root Announcement information element" + */ +struct ieee80211_rann_ie { + u8 rann_flags; + u8 rann_hopcount; + u8 rann_ttl; + u8 rann_addr[6]; + u32 rann_seq; + u32 rann_metric; +} __attribute__ ((packed)); + #define WLAN_SA_QUERY_TR_ID_LEN 2 struct ieee80211_mgmt { @@ -1070,6 +1084,7 @@ enum ieee80211_eid { WLAN_EID_PREQ = 68, WLAN_EID_PREP = 69, WLAN_EID_PERR = 70, + WLAN_EID_RANN = 49, /* compatible with FreeBSD */ /* 802.11h */ WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 19b0c128d94..2a7d3d4067e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -804,6 +804,7 @@ struct ieee802_11_elems { u8 *preq; u8 *prep; u8 *perr; + struct ieee80211_rann_ie *rann; u8 *ch_switch_elem; u8 *country_elem; u8 *pwr_constr_elem; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index db1a33098a8..7b9dd87cf9f 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -28,6 +28,8 @@ /* Reply and forward */ #define MP_F_RF 0x2 +static void mesh_queue_preq(struct mesh_path *, u8); + static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) { if (ae) @@ -81,7 +83,8 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) enum mpath_frame_type { MPATH_PREQ = 0, MPATH_PREP, - MPATH_PERR + MPATH_PERR, + MPATH_RANN }; static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, @@ -109,7 +112,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - /* BSSID is left zeroed, wildcard value */ + /* BSSID == SA */ + memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; @@ -126,6 +130,12 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; break; + case MPATH_RANN: + mhwmp_dbg("sending RANN from %pM\n", orig_addr); + ie_len = sizeof(struct ieee80211_rann_ie); + pos = skb_put(skb, 2 + ie_len); + *pos++ = WLAN_EID_RANN; + break; default: kfree_skb(skb); return -ENOTSUPP; @@ -143,8 +153,10 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, pos += ETH_ALEN; memcpy(pos, &orig_dsn, 4); pos += 4; - memcpy(pos, &lifetime, 4); - pos += 4; + if (action != MPATH_RANN) { + memcpy(pos, &lifetime, 4); + pos += 4; + } memcpy(pos, &metric, 4); pos += 4; if (action == MPATH_PREQ) { @@ -152,9 +164,11 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, *pos++ = 1; *pos++ = dst_flags; } - memcpy(pos, dst, ETH_ALEN); - pos += ETH_ALEN; - memcpy(pos, &dst_dsn, 4); + if (action != MPATH_RANN) { + memcpy(pos, dst, ETH_ALEN); + pos += ETH_ALEN; + memcpy(pos, &dst_dsn, 4); + } ieee80211_tx_skb(sdata, skb, 1); return 0; @@ -610,6 +624,54 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); } +static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, + struct ieee80211_rann_ie *rann) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct mesh_path *mpath; + u8 *ta; + u8 ttl, flags, hopcount; + u8 *orig_addr; + u32 orig_dsn, metric; + + ta = mgmt->sa; + ttl = rann->rann_ttl; + if (ttl <= 1) { + ifmsh->mshstats.dropped_frames_ttl++; + return; + } + ttl--; + flags = rann->rann_flags; + orig_addr = rann->rann_addr; + orig_dsn = rann->rann_seq; + hopcount = rann->rann_hopcount; + metric = rann->rann_metric; + mhwmp_dbg("received RANN from %pM\n", orig_addr); + + rcu_read_lock(); + mpath = mesh_path_lookup(orig_addr, sdata); + if (!mpath) { + mesh_path_add(orig_addr, sdata); + mpath = mesh_path_lookup(orig_addr, sdata); + if (!mpath) { + rcu_read_unlock(); + sdata->u.mesh.mshstats.dropped_frames_no_route++; + return; + } + mesh_queue_preq(mpath, + PREQ_Q_F_START | PREQ_Q_F_REFRESH); + } + if (mpath->dsn < orig_dsn) { + mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, + cpu_to_le32(orig_dsn), + 0, NULL, 0, sdata->dev->broadcast, + hopcount, ttl, 0, cpu_to_le32(metric), + 0, sdata); + mpath->dsn = orig_dsn; + } + rcu_read_unlock(); +} void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, @@ -654,7 +716,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, return; hwmp_perr_frame_process(sdata, mgmt, elems.perr); } - + if (elems.rann) + hwmp_rann_frame_process(sdata, mgmt, elems.rann); } /** diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aedbaaa067e..da86e1592f8 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -685,6 +685,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, elems->perr = pos; elems->perr_len = elen; break; + case WLAN_EID_RANN: + if (elen >= sizeof(struct ieee80211_rann_ie)) + elems->rann = (void *)pos; + break; case WLAN_EID_CHANNEL_SWITCH: elems->ch_switch_elem = pos; elems->ch_switch_elem_len = elen; -- cgit v1.2.3 From d611f062f4351d8609910648854908fecf58970d Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:50 +0000 Subject: mac80211: update PERR frame format Update the PERR IE frame format according to latest draft (3.03). Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh.h | 9 +++++-- net/mac80211/mesh_hwmp.c | 58 ++++++++++++++++++++++++++++++++++++++------- net/mac80211/mesh_pathtbl.c | 6 +++-- 3 files changed, 60 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2fd3e200a06..1d534c70240 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -210,6 +210,11 @@ struct mesh_rmc { #define MESH_PATH_SEL_CATEGORY 32 #define MESH_PATH_SEL_ACTION 0 +/* PERR reason codes */ +#define PEER_RCODE_UNSPECIFIED 11 +#define PERR_RCODE_NO_ROUTE 12 +#define PERR_RCODE_DEST_UNREACH 13 + /* Public interfaces */ /* Various */ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, @@ -275,8 +280,8 @@ void mesh_mpp_table_grow(void); u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl); /* Mesh paths */ -int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, - struct ieee80211_sub_if_data *sdata); +int mesh_path_error_tx(u8 ttl, u8 *dest, __le32 dest_dsn, __le16 dest_rcode, + u8 *ra, struct ieee80211_sub_if_data *sdata); void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); void mesh_path_flush_pending(struct mesh_path *mpath); void mesh_path_tx_pending(struct mesh_path *mpath); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 7b9dd87cf9f..eb4180bff57 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -27,6 +27,10 @@ #define MP_F_DO 0x1 /* Reply and forward */ #define MP_F_RF 0x2 +/* Unknown Sequence Number */ +#define MP_F_USN 0x01 +/* Reason code Present */ +#define MP_F_RCODE 0x02 static void mesh_queue_preq(struct mesh_path *, u8); @@ -37,6 +41,13 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) return get_unaligned_le32(preq_elem + offset); } +static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) +{ + if (ae) + offset += 6; + return get_unaligned_le16(preq_elem + offset); +} + /* HWMP IE processing macros */ #define AE_F (1<<6) #define AE_F_SET(x) (*x & AE_F) @@ -63,8 +74,11 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) #define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) #define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); -#define PERR_IE_DST_ADDR(x) (x + 2) -#define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); +#define PERR_IE_TTL(x) (*(x)) +#define PERR_IE_DST_FLAGS(x) (*(x + 2)) +#define PERR_IE_DST_ADDR(x) (x + 3) +#define PERR_IE_DST_DSN(x) u32_field_get(x, 9, 0); +#define PERR_IE_DST_RCODE(x) u16_field_get(x, 13, 0); #define MSEC_TO_TU(x) (x*1000/1024) #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) @@ -181,8 +195,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, * @dst_dsn: dsn of the broken destination * @ra: node this frame is addressed to */ -int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, - struct ieee80211_sub_if_data *sdata) +int mesh_path_error_tx(u8 ttl, u8 *dst, __le32 dst_dsn, __le16 dst_rcode, + u8 *ra, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); @@ -207,17 +221,29 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, /* BSSID is left zeroed, wildcard value */ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; - ie_len = 12; + ie_len = 15; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PERR; *pos++ = ie_len; - /* mode flags, reserved */ - *pos++ = 0; + /* ttl */ + *pos++ = MESH_TTL; /* number of destinations */ *pos++ = 1; + /* + * flags bit, bit 1 is unset if we know the sequence number and + * bit 2 is set if we have a reason code + */ + *pos = 0; + if (!dst_dsn) + *pos |= MP_F_USN; + if (dst_rcode) + *pos |= MP_F_RCODE; + pos++; memcpy(pos, dst, ETH_ALEN); pos += ETH_ALEN; memcpy(pos, &dst_dsn, 4); + pos += 4; + memcpy(pos, &dst_rcode, 2); ieee80211_tx_skb(sdata, skb, 1); return 0; @@ -598,13 +624,26 @@ fail: static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, u8 *perr_elem) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; + u8 ttl; u8 *ta, *dst_addr; + u8 dst_flags; u32 dst_dsn; + u16 dst_rcode; ta = mgmt->sa; + ttl = PERR_IE_TTL(perr_elem); + if (ttl <= 1) { + ifmsh->mshstats.dropped_frames_ttl++; + return; + } + ttl--; + dst_flags = PERR_IE_DST_FLAGS(perr_elem); dst_addr = PERR_IE_DST_ADDR(perr_elem); dst_dsn = PERR_IE_DST_DSN(perr_elem); + dst_rcode = PERR_IE_DST_RCODE(perr_elem); + rcu_read_lock(); mpath = mesh_path_lookup(dst_addr, sdata); if (mpath) { @@ -616,7 +655,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, mpath->flags &= ~MESH_PATH_ACTIVE; mpath->dsn = dst_dsn; spin_unlock_bh(&mpath->state_lock); - mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), + mesh_path_error_tx(ttl, dst_addr, cpu_to_le32(dst_dsn), + cpu_to_le16(dst_rcode), sdata->dev->broadcast, sdata); } else spin_unlock_bh(&mpath->state_lock); @@ -711,7 +751,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, last_hop_metric); } if (elems.perr) { - if (elems.perr_len != 12) + if (elems.perr_len != 15) /* Right now we support only one destination per PERR */ return; hwmp_perr_frame_process(sdata, mgmt, elems.perr); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 751c4d0e2b3..5d541235ca2 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -465,8 +465,9 @@ void mesh_plink_broken(struct sta_info *sta) mpath->flags &= ~MESH_PATH_ACTIVE; ++mpath->dsn; spin_unlock_bh(&mpath->state_lock); - mesh_path_error_tx(mpath->dst, + mesh_path_error_tx(MESH_TTL, mpath->dst, cpu_to_le32(mpath->dsn), + PERR_RCODE_DEST_UNREACH, sdata->dev->broadcast, sdata); } else spin_unlock_bh(&mpath->state_lock); @@ -611,7 +612,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, mpath = mesh_path_lookup(da, sdata); if (mpath) dsn = ++mpath->dsn; - mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, sdata); + mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(dsn), + PERR_RCODE_NO_ROUTE, ra, sdata); } kfree_skb(skb); -- cgit v1.2.3 From a6a58b4f14106e61e5d78aac7995686ed0d5eab8 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:51 +0000 Subject: mac80211: properly forward the RANN IE Increase hopcount and convert metric to LE before forwarding the RANN action frame. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index eb4180bff57..7d36f3a741a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -686,6 +686,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, orig_addr = rann->rann_addr; orig_dsn = rann->rann_seq; hopcount = rann->rann_hopcount; + hopcount++; metric = rann->rann_metric; mhwmp_dbg("received RANN from %pM\n", orig_addr); @@ -706,7 +707,8 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, cpu_to_le32(orig_dsn), 0, NULL, 0, sdata->dev->broadcast, - hopcount, ttl, 0, cpu_to_le32(metric), + hopcount, ttl, 0, + cpu_to_le32(metric + mpath->metric), 0, sdata); mpath->dsn = orig_dsn; } -- cgit v1.2.3 From 77fa76bb7f5589cd336e4da4a02e2d685b70ce0a Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:52 +0000 Subject: mac80211: set the AID field correctly for mesh peer frames This sets the AID field correctly for mesh peer confirm frames. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index cf12f616c5b..ec68d2046d2 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -181,7 +181,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, if (action == PLINK_CONFIRM) { pos = skb_put(skb, 4); /* two-byte status code followed by two-byte AID */ - memset(pos, 0, 4); + memset(pos, 0, 2); + memcpy(pos + 2, &plid, 2); } mesh_mgmt_ies_add(skb, sdata); } -- cgit v1.2.3 From 36f0d5f537885179c8fa92a70d4fcfb3a336b082 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:53 +0000 Subject: mac80211: fix BSSID setup for beacon frames BSSID is now set to the TA. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2f3345c5f7c..3ad053f6de1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2148,7 +2148,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - /* BSSID is left zeroed, wildcard value */ + memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(sdata->vif.bss_conf.beacon_int); mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ -- cgit v1.2.3 From be125c60e46e165fbfe33db36a4a9d943d560a5b Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:54 +0000 Subject: mac80211: add the DS params to the beacon Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 63427d98321..222a3133839 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -247,6 +247,13 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) } } + if (sband->band == IEEE80211_BAND_2GHZ) { + pos = skb_put(skb, 2 + 1); + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); + } + pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); *pos++ = WLAN_EID_MESH_ID; *pos++ = sdata->u.mesh.mesh_id_len; -- cgit v1.2.3 From d19b3bf6384e66ac6e11a61ee31ed2cfe149f4d8 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:55 +0000 Subject: mac80211: replace "destination" with "target" to follow the spec Resulting object files have the same MD5 as before. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- include/linux/nl80211.h | 8 +- include/net/cfg80211.h | 8 +- net/mac80211/cfg.c | 8 +- net/mac80211/ieee80211_i.h | 10 +- net/mac80211/mesh.c | 2 +- net/mac80211/mesh.h | 10 +- net/mac80211/mesh_hwmp.c | 221 ++++++++++++++++++++++---------------------- net/mac80211/mesh_pathtbl.c | 12 +-- net/wireless/nl80211.c | 6 +- 9 files changed, 144 insertions(+), 141 deletions(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 203adef972c..7a0bd6ea6f6 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -899,14 +899,14 @@ enum nl80211_sta_info { * * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running - * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN + * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded */ enum nl80211_mpath_flags { NL80211_MPATH_FLAG_ACTIVE = 1<<0, NL80211_MPATH_FLAG_RESOLVING = 1<<1, - NL80211_MPATH_FLAG_DSN_VALID = 1<<2, + NL80211_MPATH_FLAG_SN_VALID = 1<<2, NL80211_MPATH_FLAG_FIXED = 1<<3, NL80211_MPATH_FLAG_RESOLVED = 1<<4, }; @@ -919,7 +919,7 @@ enum nl80211_mpath_flags { * * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination - * @NL80211_ATTR_MPATH_DSN: destination sequence number + * @NL80211_ATTR_MPATH_SN: destination sequence number * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in @@ -930,7 +930,7 @@ enum nl80211_mpath_flags { enum nl80211_mpath_info { __NL80211_MPATH_INFO_INVALID, NL80211_MPATH_INFO_FRAME_QLEN, - NL80211_MPATH_INFO_DSN, + NL80211_MPATH_INFO_SN, NL80211_MPATH_INFO_METRIC, NL80211_MPATH_INFO_EXPTIME, NL80211_MPATH_INFO_FLAGS, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1ee41e4a92e..7d0ae9c1828 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -420,7 +420,7 @@ enum monitor_flags { * in during get_station() or dump_station(). * * MPATH_INFO_FRAME_QLEN: @frame_qlen filled - * MPATH_INFO_DSN: @dsn filled + * MPATH_INFO_SN: @sn filled * MPATH_INFO_METRIC: @metric filled * MPATH_INFO_EXPTIME: @exptime filled * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled @@ -429,7 +429,7 @@ enum monitor_flags { */ enum mpath_info_flags { MPATH_INFO_FRAME_QLEN = BIT(0), - MPATH_INFO_DSN = BIT(1), + MPATH_INFO_SN = BIT(1), MPATH_INFO_METRIC = BIT(2), MPATH_INFO_EXPTIME = BIT(3), MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), @@ -444,7 +444,7 @@ enum mpath_info_flags { * * @filled: bitfield of flags from &enum mpath_info_flags * @frame_qlen: number of queued frames for this destination - * @dsn: destination sequence number + * @sn: target sequence number * @metric: metric (cost) of this mesh path * @exptime: expiration time for the mesh path from now, in msecs * @flags: mesh path flags @@ -458,7 +458,7 @@ enum mpath_info_flags { struct mpath_info { u32 filled; u32 frame_qlen; - u32 dsn; + u32 sn; u32 metric; u32 exptime; u32 discovery_timeout; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 576b86f81d1..81053587e72 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -935,7 +935,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, pinfo->generation = mesh_paths_generation; pinfo->filled = MPATH_INFO_FRAME_QLEN | - MPATH_INFO_DSN | + MPATH_INFO_SN | MPATH_INFO_METRIC | MPATH_INFO_EXPTIME | MPATH_INFO_DISCOVERY_TIMEOUT | @@ -943,7 +943,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, MPATH_INFO_FLAGS; pinfo->frame_qlen = mpath->frame_queue.qlen; - pinfo->dsn = mpath->dsn; + pinfo->sn = mpath->sn; pinfo->metric = mpath->metric; if (time_before(jiffies, mpath->exp_time)) pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); @@ -955,8 +955,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; if (mpath->flags & MESH_PATH_RESOLVING) pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; - if (mpath->flags & MESH_PATH_DSN_VALID) - pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; + if (mpath->flags & MESH_PATH_SN_VALID) + pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID; if (mpath->flags & MESH_PATH_FIXED) pinfo->flags |= NL80211_MPATH_FLAG_FIXED; if (mpath->flags & MESH_PATH_RESOLVING) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2a7d3d4067e..fb54ddb9b27 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -373,14 +373,14 @@ struct ieee80211_if_mesh { u8 mesh_sp_id; /* Authentication Protocol Identifier */ u8 mesh_auth_id; - /* Local mesh Destination Sequence Number */ - u32 dsn; + /* Local mesh Sequence Number */ + u32 sn; /* Last used PREQ ID */ u32 preq_id; atomic_t mpaths; - /* Timestamp of last DSN update */ - unsigned long last_dsn_update; - /* Timestamp of last DSN sent */ + /* Timestamp of last SN update */ + unsigned long last_sn_update; + /* Timestamp of last SN sent */ unsigned long last_preq; struct mesh_rmc *rmc; spinlock_t mesh_preq_queue_lock; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 222a3133839..0f3e1147ec4 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -672,7 +672,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) MESH_MIN_DISCOVERY_TIMEOUT; ifmsh->accepting_plinks = true; ifmsh->preq_id = 0; - ifmsh->dsn = 0; + ifmsh->sn = 0; atomic_set(&ifmsh->mpaths, 0); mesh_rmc_init(sdata); ifmsh->last_preq = jiffies; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 1d534c70240..ee687add392 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -26,7 +26,7 @@ * * @MESH_PATH_ACTIVE: the mesh path can be used for forwarding * @MESH_PATH_RESOLVING: the discovery process is running for this mesh path - * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence + * @MESH_PATH_SN_VALID: the mesh path contains a valid destination sequence * number * @MESH_PATH_FIXED: the mesh path has been manually set and should not be * modified @@ -38,7 +38,7 @@ enum mesh_path_flags { MESH_PATH_ACTIVE = BIT(0), MESH_PATH_RESOLVING = BIT(1), - MESH_PATH_DSN_VALID = BIT(2), + MESH_PATH_SN_VALID = BIT(2), MESH_PATH_FIXED = BIT(3), MESH_PATH_RESOLVED = BIT(4), }; @@ -70,7 +70,7 @@ enum mesh_deferred_task_flags { * @timer: mesh path discovery timer * @frame_queue: pending queue for frames sent to this destination while the * path is unresolved - * @dsn: destination sequence number of the destination + * @sn: target sequence number * @metric: current metric to this destination * @hop_count: hops to destination * @exp_time: in jiffies, when the path will expire or when it expired @@ -94,7 +94,7 @@ struct mesh_path { struct timer_list timer; struct sk_buff_head frame_queue; struct rcu_head rcu; - u32 dsn; + u32 sn; u32 metric; u8 hop_count; unsigned long exp_time; @@ -280,7 +280,7 @@ void mesh_mpp_table_grow(void); u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl); /* Mesh paths */ -int mesh_path_error_tx(u8 ttl, u8 *dest, __le32 dest_dsn, __le16 dest_rcode, +int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, u8 *ra, struct ieee80211_sub_if_data *sdata); void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); void mesh_path_flush_pending(struct mesh_path *mpath); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 7d36f3a741a..f03a27dfd61 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -56,33 +56,33 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) #define PREQ_IE_TTL(x) (*(x + 2)) #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) #define PREQ_IE_ORIG_ADDR(x) (x + 7) -#define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0); +#define PREQ_IE_ORIG_SN(x) u32_field_get(x, 13, 0); #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); #define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)); -#define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) -#define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) -#define PREQ_IE_DST_DSN(x) u32_field_get(x, 33, AE_F_SET(x)); +#define PREQ_IE_TARGET_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) +#define PREQ_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) +#define PREQ_IE_TARGET_SN(x) u32_field_get(x, 33, AE_F_SET(x)); #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) #define PREP_IE_TTL(x) PREQ_IE_TTL(x) #define PREP_IE_ORIG_ADDR(x) (x + 3) -#define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0); +#define PREP_IE_ORIG_SN(x) u32_field_get(x, 9, 0); #define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); #define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)); -#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) -#define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); +#define PREP_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) +#define PREP_IE_TARGET_SN(x) u32_field_get(x, 27, AE_F_SET(x)); #define PERR_IE_TTL(x) (*(x)) -#define PERR_IE_DST_FLAGS(x) (*(x + 2)) -#define PERR_IE_DST_ADDR(x) (x + 3) -#define PERR_IE_DST_DSN(x) u32_field_get(x, 9, 0); -#define PERR_IE_DST_RCODE(x) u16_field_get(x, 13, 0); +#define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) +#define PERR_IE_TARGET_ADDR(x) (x + 3) +#define PERR_IE_TARGET_SN(x) u32_field_get(x, 9, 0); +#define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0); #define MSEC_TO_TU(x) (x*1000/1024) -#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) -#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) +#define SN_GT(x, y) ((long) (y) - (long) (x) < 0) +#define SN_LT(x, y) ((long) (x) - (long) (y) < 0) #define net_traversal_jiffies(s) \ msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) @@ -102,9 +102,10 @@ enum mpath_frame_type { }; static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, - u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst, - __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, - __le32 metric, __le32 preq_id, struct ieee80211_sub_if_data *sdata) + u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target, + __le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime, + __le32 metric, __le32 preq_id, + struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); @@ -133,13 +134,13 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, switch (action) { case MPATH_PREQ: - mhwmp_dbg("sending PREQ to %pM\n", dst); + mhwmp_dbg("sending PREQ to %pM\n", target); ie_len = 37; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREQ; break; case MPATH_PREP: - mhwmp_dbg("sending PREP to %pM\n", dst); + mhwmp_dbg("sending PREP to %pM\n", target); ie_len = 31; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; @@ -165,7 +166,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, } memcpy(pos, orig_addr, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &orig_dsn, 4); + memcpy(pos, &orig_sn, 4); pos += 4; if (action != MPATH_RANN) { memcpy(pos, &lifetime, 4); @@ -176,12 +177,12 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, if (action == MPATH_PREQ) { /* destination count */ *pos++ = 1; - *pos++ = dst_flags; + *pos++ = target_flags; } if (action != MPATH_RANN) { - memcpy(pos, dst, ETH_ALEN); + memcpy(pos, target, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &dst_dsn, 4); + memcpy(pos, &target_sn, 4); } ieee80211_tx_skb(sdata, skb, 1); @@ -191,12 +192,14 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, /** * mesh_send_path error - Sends a PERR mesh management frame * - * @dst: broken destination - * @dst_dsn: dsn of the broken destination + * @target: broken destination + * @target_sn: SN of the broken destination + * @target_rcode: reason code for this PERR * @ra: node this frame is addressed to */ -int mesh_path_error_tx(u8 ttl, u8 *dst, __le32 dst_dsn, __le16 dst_rcode, - u8 *ra, struct ieee80211_sub_if_data *sdata) +int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, + __le16 target_rcode, u8 *ra, + struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); @@ -234,16 +237,16 @@ int mesh_path_error_tx(u8 ttl, u8 *dst, __le32 dst_dsn, __le16 dst_rcode, * bit 2 is set if we have a reason code */ *pos = 0; - if (!dst_dsn) + if (!target_sn) *pos |= MP_F_USN; - if (dst_rcode) + if (target_rcode) *pos |= MP_F_RCODE; pos++; - memcpy(pos, dst, ETH_ALEN); + memcpy(pos, target, ETH_ALEN); pos += ETH_ALEN; - memcpy(pos, &dst_dsn, 4); + memcpy(pos, &target_sn, 4); pos += 4; - memcpy(pos, &dst_rcode, 2); + memcpy(pos, &target_rcode, 2); ieee80211_tx_skb(sdata, skb, 1); return 0; @@ -324,7 +327,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, struct sta_info *sta; bool fresh_info; u8 *orig_addr, *ta; - u32 orig_dsn, orig_metric; + u32 orig_sn, orig_metric; unsigned long orig_lifetime, exp_time; u32 last_hop_metric, new_metric; bool process = true; @@ -343,7 +346,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, switch (action) { case MPATH_PREQ: orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); - orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie); + orig_sn = PREQ_IE_ORIG_SN(hwmp_ie); orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); orig_metric = PREQ_IE_METRIC(hwmp_ie); break; @@ -356,7 +359,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, * information from both PREQ and PREP frames. */ orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); - orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie); + orig_sn = PREP_IE_ORIG_SN(hwmp_ie); orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); orig_metric = PREP_IE_METRIC(hwmp_ie); break; @@ -382,9 +385,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, if (mpath->flags & MESH_PATH_FIXED) fresh_info = false; else if ((mpath->flags & MESH_PATH_ACTIVE) && - (mpath->flags & MESH_PATH_DSN_VALID)) { - if (DSN_GT(mpath->dsn, orig_dsn) || - (mpath->dsn == orig_dsn && + (mpath->flags & MESH_PATH_SN_VALID)) { + if (SN_GT(mpath->sn, orig_sn) || + (mpath->sn == orig_sn && action == MPATH_PREQ && new_metric > mpath->metric)) { process = false; @@ -403,9 +406,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, if (fresh_info) { mesh_path_assign_nexthop(mpath, sta); - mpath->flags |= MESH_PATH_DSN_VALID; + mpath->flags |= MESH_PATH_SN_VALID; mpath->metric = new_metric; - mpath->dsn = orig_dsn; + mpath->sn = orig_sn; mpath->exp_time = time_after(mpath->exp_time, exp_time) ? mpath->exp_time : exp_time; mesh_path_activate(mpath); @@ -444,7 +447,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, if (fresh_info) { mesh_path_assign_nexthop(mpath, sta); - mpath->flags &= ~MESH_PATH_DSN_VALID; + mpath->flags &= ~MESH_PATH_SN_VALID; mpath->metric = last_hop_metric; mpath->exp_time = time_after(mpath->exp_time, exp_time) ? mpath->exp_time : exp_time; @@ -466,47 +469,47 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; - u8 *dst_addr, *orig_addr; - u8 dst_flags, ttl; - u32 orig_dsn, dst_dsn, lifetime; + u8 *target_addr, *orig_addr; + u8 target_flags, ttl; + u32 orig_sn, target_sn, lifetime; bool reply = false; bool forward = true; - /* Update destination DSN, if present */ - dst_addr = PREQ_IE_DST_ADDR(preq_elem); + /* Update target SN, if present */ + target_addr = PREQ_IE_TARGET_ADDR(preq_elem); orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); - dst_dsn = PREQ_IE_DST_DSN(preq_elem); - orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); - dst_flags = PREQ_IE_DST_F(preq_elem); + target_sn = PREQ_IE_TARGET_SN(preq_elem); + orig_sn = PREQ_IE_ORIG_SN(preq_elem); + target_flags = PREQ_IE_TARGET_F(preq_elem); mhwmp_dbg("received PREQ from %pM\n", orig_addr); - if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { + if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { mhwmp_dbg("PREQ is for us\n"); forward = false; reply = true; metric = 0; - if (time_after(jiffies, ifmsh->last_dsn_update + + if (time_after(jiffies, ifmsh->last_sn_update + net_traversal_jiffies(sdata)) || - time_before(jiffies, ifmsh->last_dsn_update)) { - dst_dsn = ++ifmsh->dsn; - ifmsh->last_dsn_update = jiffies; + time_before(jiffies, ifmsh->last_sn_update)) { + target_sn = ++ifmsh->sn; + ifmsh->last_sn_update = jiffies; } } else { rcu_read_lock(); - mpath = mesh_path_lookup(dst_addr, sdata); + mpath = mesh_path_lookup(target_addr, sdata); if (mpath) { - if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || - DSN_LT(mpath->dsn, dst_dsn)) { - mpath->dsn = dst_dsn; - mpath->flags |= MESH_PATH_DSN_VALID; - } else if ((!(dst_flags & MP_F_DO)) && + if ((!(mpath->flags & MESH_PATH_SN_VALID)) || + SN_LT(mpath->sn, target_sn)) { + mpath->sn = target_sn; + mpath->flags |= MESH_PATH_SN_VALID; + } else if ((!(target_flags & MP_F_DO)) && (mpath->flags & MESH_PATH_ACTIVE)) { reply = true; metric = mpath->metric; - dst_dsn = mpath->dsn; - if (dst_flags & MP_F_RF) - dst_flags |= MP_F_DO; + target_sn = mpath->sn; + if (target_flags & MP_F_RF) + target_flags |= MP_F_DO; else forward = false; } @@ -519,9 +522,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, ttl = ifmsh->mshcfg.dot11MeshTTL; if (ttl != 0) { mhwmp_dbg("replying to the PREQ\n"); - mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, - cpu_to_le32(dst_dsn), 0, orig_addr, - cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, + mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr, + cpu_to_le32(target_sn), 0, orig_addr, + cpu_to_le32(orig_sn), mgmt->sa, 0, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); } else @@ -544,8 +547,8 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, preq_id = PREQ_IE_PREQ_ID(preq_elem); hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, - cpu_to_le32(orig_dsn), dst_flags, dst_addr, - cpu_to_le32(dst_dsn), sdata->dev->broadcast, + cpu_to_le32(orig_sn), target_flags, target_addr, + cpu_to_le32(target_sn), sdata->dev->broadcast, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); @@ -560,10 +563,10 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, u8 *prep_elem, u32 metric) { struct mesh_path *mpath; - u8 *dst_addr, *orig_addr; + u8 *target_addr, *orig_addr; u8 ttl, hopcount, flags; u8 next_hop[ETH_ALEN]; - u32 dst_dsn, orig_dsn, lifetime; + u32 target_sn, orig_sn, lifetime; mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem)); @@ -573,8 +576,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, * which corresponds with the originator of the PREQ which this PREP * replies */ - dst_addr = PREP_IE_DST_ADDR(prep_elem); - if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) + target_addr = PREP_IE_TARGET_ADDR(prep_elem); + if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) /* destination, no forwarding required */ return; @@ -585,7 +588,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, } rcu_read_lock(); - mpath = mesh_path_lookup(dst_addr, sdata); + mpath = mesh_path_lookup(target_addr, sdata); if (mpath) spin_lock_bh(&mpath->state_lock); else @@ -601,13 +604,13 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, lifetime = PREP_IE_LIFETIME(prep_elem); hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; orig_addr = PREP_IE_ORIG_ADDR(prep_elem); - dst_dsn = PREP_IE_DST_DSN(prep_elem); - orig_dsn = PREP_IE_ORIG_DSN(prep_elem); + target_sn = PREP_IE_TARGET_SN(prep_elem); + orig_sn = PREP_IE_ORIG_SN(prep_elem); mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, - cpu_to_le32(orig_dsn), 0, dst_addr, - cpu_to_le32(dst_dsn), mpath->next_hop->sta.addr, hopcount, ttl, - cpu_to_le32(lifetime), cpu_to_le32(metric), + cpu_to_le32(orig_sn), 0, target_addr, + cpu_to_le32(target_sn), mpath->next_hop->sta.addr, hopcount, + ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); @@ -627,10 +630,10 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; u8 ttl; - u8 *ta, *dst_addr; - u8 dst_flags; - u32 dst_dsn; - u16 dst_rcode; + u8 *ta, *target_addr; + u8 target_flags; + u32 target_sn; + u16 target_rcode; ta = mgmt->sa; ttl = PERR_IE_TTL(perr_elem); @@ -639,24 +642,24 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, return; } ttl--; - dst_flags = PERR_IE_DST_FLAGS(perr_elem); - dst_addr = PERR_IE_DST_ADDR(perr_elem); - dst_dsn = PERR_IE_DST_DSN(perr_elem); - dst_rcode = PERR_IE_DST_RCODE(perr_elem); + target_flags = PERR_IE_TARGET_FLAGS(perr_elem); + target_addr = PERR_IE_TARGET_ADDR(perr_elem); + target_sn = PERR_IE_TARGET_SN(perr_elem); + target_rcode = PERR_IE_TARGET_RCODE(perr_elem); rcu_read_lock(); - mpath = mesh_path_lookup(dst_addr, sdata); + mpath = mesh_path_lookup(target_addr, sdata); if (mpath) { spin_lock_bh(&mpath->state_lock); if (mpath->flags & MESH_PATH_ACTIVE && memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && - (!(mpath->flags & MESH_PATH_DSN_VALID) || - DSN_GT(dst_dsn, mpath->dsn))) { + (!(mpath->flags & MESH_PATH_SN_VALID) || + SN_GT(target_sn, mpath->sn))) { mpath->flags &= ~MESH_PATH_ACTIVE; - mpath->dsn = dst_dsn; + mpath->sn = target_sn; spin_unlock_bh(&mpath->state_lock); - mesh_path_error_tx(ttl, dst_addr, cpu_to_le32(dst_dsn), - cpu_to_le16(dst_rcode), + mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), + cpu_to_le16(target_rcode), sdata->dev->broadcast, sdata); } else spin_unlock_bh(&mpath->state_lock); @@ -673,7 +676,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, u8 *ta; u8 ttl, flags, hopcount; u8 *orig_addr; - u32 orig_dsn, metric; + u32 orig_sn, metric; ta = mgmt->sa; ttl = rann->rann_ttl; @@ -684,7 +687,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ttl--; flags = rann->rann_flags; orig_addr = rann->rann_addr; - orig_dsn = rann->rann_seq; + orig_sn = rann->rann_seq; hopcount = rann->rann_hopcount; hopcount++; metric = rann->rann_metric; @@ -703,14 +706,14 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); } - if (mpath->dsn < orig_dsn) { + if (mpath->sn < orig_sn) { mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, - cpu_to_le32(orig_dsn), + cpu_to_le32(orig_sn), 0, NULL, 0, sdata->dev->broadcast, hopcount, ttl, 0, cpu_to_le32(metric + mpath->metric), 0, sdata); - mpath->dsn = orig_dsn; + mpath->sn = orig_sn; } rcu_read_unlock(); } @@ -823,7 +826,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_preq_queue *preq_node; struct mesh_path *mpath; - u8 ttl, dst_flags; + u8 ttl, target_flags; u32 lifetime; spin_lock_bh(&ifmsh->mesh_preq_queue_lock); @@ -865,11 +868,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) ifmsh->last_preq = jiffies; - if (time_after(jiffies, ifmsh->last_dsn_update + + if (time_after(jiffies, ifmsh->last_sn_update + net_traversal_jiffies(sdata)) || - time_before(jiffies, ifmsh->last_dsn_update)) { - ++ifmsh->dsn; - sdata->u.mesh.last_dsn_update = jiffies; + time_before(jiffies, ifmsh->last_sn_update)) { + ++ifmsh->sn; + sdata->u.mesh.last_sn_update = jiffies; } lifetime = default_lifetime(sdata); ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; @@ -880,14 +883,14 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) } if (preq_node->flags & PREQ_Q_F_REFRESH) - dst_flags = MP_F_DO; + target_flags = MP_F_DO; else - dst_flags = MP_F_RF; + target_flags = MP_F_RF; spin_unlock_bh(&mpath->state_lock); mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, - cpu_to_le32(ifmsh->dsn), dst_flags, mpath->dst, - cpu_to_le32(mpath->dsn), sdata->dev->broadcast, 0, + cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, + cpu_to_le32(mpath->sn), sdata->dev->broadcast, 0, ttl, cpu_to_le32(lifetime), 0, cpu_to_le32(ifmsh->preq_id++), sdata); mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); @@ -914,15 +917,15 @@ int mesh_nexthop_lookup(struct sk_buff *skb, struct sk_buff *skb_to_free = NULL; struct mesh_path *mpath; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u8 *dst_addr = hdr->addr3; + u8 *target_addr = hdr->addr3; int err = 0; rcu_read_lock(); - mpath = mesh_path_lookup(dst_addr, sdata); + mpath = mesh_path_lookup(target_addr, sdata); if (!mpath) { - mesh_path_add(dst_addr, sdata); - mpath = mesh_path_lookup(dst_addr, sdata); + mesh_path_add(target_addr, sdata); + mpath = mesh_path_lookup(target_addr, sdata); if (!mpath) { sdata->u.mesh.mshstats.dropped_frames_no_route++; err = -ENOSPC; diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 5d541235ca2..2cebdf52b7b 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -463,10 +463,10 @@ void mesh_plink_broken(struct sta_info *sta) mpath->flags & MESH_PATH_ACTIVE && !(mpath->flags & MESH_PATH_FIXED)) { mpath->flags &= ~MESH_PATH_ACTIVE; - ++mpath->dsn; + ++mpath->sn; spin_unlock_bh(&mpath->state_lock); mesh_path_error_tx(MESH_TTL, mpath->dst, - cpu_to_le32(mpath->dsn), + cpu_to_le32(mpath->sn), PERR_RCODE_DEST_UNREACH, sdata->dev->broadcast, sdata); } else @@ -602,7 +602,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct mesh_path *mpath; - u32 dsn = 0; + u32 sn = 0; if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { u8 *ra, *da; @@ -611,8 +611,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, ra = hdr->addr1; mpath = mesh_path_lookup(da, sdata); if (mpath) - dsn = ++mpath->dsn; - mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(dsn), + sn = ++mpath->sn; + mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn), PERR_RCODE_NO_ROUTE, ra, sdata); } @@ -648,7 +648,7 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) { spin_lock_bh(&mpath->state_lock); mesh_path_assign_nexthop(mpath, next_hop); - mpath->dsn = 0xffff; + mpath->sn = 0xffff; mpath->metric = 0; mpath->hop_count = 0; mpath->exp_time = 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8c8e4eae6a1..7c199987250 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2116,9 +2116,9 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, if (pinfo->filled & MPATH_INFO_FRAME_QLEN) NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, pinfo->frame_qlen); - if (pinfo->filled & MPATH_INFO_DSN) - NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, - pinfo->dsn); + if (pinfo->filled & MPATH_INFO_SN) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN, + pinfo->sn); if (pinfo->filled & MPATH_INFO_METRIC) NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, pinfo->metric); -- cgit v1.2.3 From e304bfd30f356f7b75d30cad0029ecca705fd590 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:56 +0000 Subject: mac80211: implement a timer to send RANN action frames RANN (Root Annoucement) frame TX. Send an action frame every second trying to build a path to all nodes on the mesh. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mesh.c | 39 +++++++++++++++++++++++++++++++++++++++ net/mac80211/mesh.h | 3 +++ net/mac80211/mesh_hwmp.c | 11 +++++++++++ 4 files changed, 54 insertions(+) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index fb54ddb9b27..b63b99fb2fd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -355,6 +355,7 @@ struct ieee80211_if_mesh { struct work_struct work; struct timer_list housekeeping_timer; struct timer_list mesh_path_timer; + struct timer_list mesh_path_root_timer; struct sk_buff_head skb_queue; unsigned long timers_running; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 0f3e1147ec4..88dcfe3030b 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -14,6 +14,7 @@ #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) +#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ) #define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */ #define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */ @@ -26,6 +27,7 @@ #define TMR_RUNNING_HK 0 #define TMR_RUNNING_MP 1 +#define TMR_RUNNING_MPR 2 int mesh_allocated; static struct kmem_cache *rm_cache; @@ -354,6 +356,23 @@ static void ieee80211_mesh_path_timer(unsigned long data) ieee80211_queue_work(&local->hw, &ifmsh->work); } +static void ieee80211_mesh_path_root_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct ieee80211_local *local = sdata->local; + + set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); + + if (local->quiescing) { + set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); + return; + } + + ieee80211_queue_work(&local->hw, &ifmsh->work); +} + /** * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame * @hdr: 802.11 frame header @@ -447,6 +466,15 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); } +static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + mesh_path_tx_root_frame(sdata); + mod_timer(&ifmsh->mesh_path_root_timer, + round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); +} + #ifdef CONFIG_PM void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) { @@ -461,6 +489,8 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); if (del_timer_sync(&ifmsh->mesh_path_timer)) set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); + if (del_timer_sync(&ifmsh->mesh_path_root_timer)) + set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); } void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) @@ -471,6 +501,8 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) add_timer(&ifmsh->housekeeping_timer); if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) add_timer(&ifmsh->mesh_path_timer); + if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) + add_timer(&ifmsh->mesh_path_root_timer); } #endif @@ -490,6 +522,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) { del_timer_sync(&sdata->u.mesh.housekeeping_timer); + del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); /* * If the timer fired while we waited for it, it will have * requeued the work. Now the work will be running again @@ -627,6 +660,9 @@ static void ieee80211_mesh_work(struct work_struct *work) if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) ieee80211_mesh_housekeeping(sdata, ifmsh); + + if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) + ieee80211_mesh_rootpath(sdata); } void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) @@ -683,6 +719,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) setup_timer(&ifmsh->mesh_path_timer, ieee80211_mesh_path_timer, (unsigned long) sdata); + setup_timer(&ifmsh->mesh_path_root_timer, + ieee80211_mesh_path_root_timer, + (unsigned long) sdata); INIT_LIST_HEAD(&ifmsh->preq_queue.list); spin_lock_init(&ifmsh->mesh_preq_queue_lock); } diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index ee687add392..00ee8425819 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -53,11 +53,13 @@ enum mesh_path_flags { * to grow. * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to * grow + * @MESH_WORK_ROOT: the mesh root station needs to send a frame */ enum mesh_deferred_task_flags { MESH_WORK_HOUSEKEEPING, MESH_WORK_GROW_MPATH_TABLE, MESH_WORK_GROW_MPP_TABLE, + MESH_WORK_ROOT, }; /** @@ -294,6 +296,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata); void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); void mesh_path_restart(struct ieee80211_sub_if_data *sdata); +void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); extern int mesh_paths_generation; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f03a27dfd61..7483894a396 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1003,3 +1003,14 @@ void mesh_path_timer(unsigned long data) endmpathtimer: rcu_read_unlock(); } + +void +mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr, + cpu_to_le32(++ifmsh->sn), + 0, NULL, 0, sdata->dev->broadcast, + 0, MESH_TTL, 0, 0, 0, sdata); +} -- cgit v1.2.3 From 63c5723bc3af8d4e86984dd4ff0c78218de418d0 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:57 +0000 Subject: mac80211: add nl80211/cfg80211 handling of the new mesh root mode option. Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- include/linux/nl80211.h | 3 +++ include/net/cfg80211.h | 1 + net/mac80211/cfg.c | 7 +++++++ net/mac80211/debugfs_netdev.c | 2 ++ net/mac80211/mesh.c | 13 +++++++++++++ net/mac80211/mesh.h | 1 + net/wireless/nl80211.c | 6 ++++++ 7 files changed, 33 insertions(+) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 7a0bd6ea6f6..d2f276de9ab 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1200,6 +1200,8 @@ enum nl80211_mntr_flags { * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) * that it takes for an HWMP information element to propagate across the mesh * + * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not + * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use @@ -1219,6 +1221,7 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + NL80211_MESHCONF_HWMP_ROOTMODE, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7d0ae9c1828..0e4c51fc63e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -508,6 +508,7 @@ struct mesh_config { u32 dot11MeshHWMPactivePathTimeout; u16 dot11MeshHWMPpreqMinInterval; u16 dot11MeshHWMPnetDiameterTraversalTime; + u8 dot11MeshHWMPRootMode; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 81053587e72..7f18c8fa188 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1029,7 +1029,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, { struct mesh_config *conf; struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_mesh *ifmsh; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ifmsh = &sdata->u.mesh; /* Set the config options which we are interested in setting */ conf = &(sdata->u.mesh.mshcfg); @@ -1064,6 +1067,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, mask)) conf->dot11MeshHWMPnetDiameterTraversalTime = nconf->dot11MeshHWMPnetDiameterTraversalTime; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOTMODE, mask)) { + conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode; + ieee80211_mesh_root_setup(ifmsh); + } return 0; } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 8782264f49e..472b2039906 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -149,6 +149,8 @@ IEEE80211_IF_FILE(path_refresh_time, u.mesh.mshcfg.path_refresh_time, DEC); IEEE80211_IF_FILE(min_discovery_timeout, u.mesh.mshcfg.min_discovery_timeout, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPRootMode, + u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); #endif diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 88dcfe3030b..05955dc6b3d 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -373,6 +373,17 @@ static void ieee80211_mesh_path_root_timer(unsigned long data) ieee80211_queue_work(&local->hw, &ifmsh->work); } +void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) +{ + if (ifmsh->mshcfg.dot11MeshHWMPRootMode) + set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); + else { + clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); + /* stop running timer */ + del_timer_sync(&ifmsh->mesh_path_root_timer); + } +} + /** * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame * @hdr: 802.11 frame header @@ -503,6 +514,7 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) add_timer(&ifmsh->mesh_path_timer); if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) add_timer(&ifmsh->mesh_path_root_timer); + ieee80211_mesh_root_setup(ifmsh); } #endif @@ -512,6 +524,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); + ieee80211_mesh_root_setup(ifmsh); ieee80211_queue_work(&local->hw, &ifmsh->work); sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 00ee8425819..5ad6975bf28 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -242,6 +242,7 @@ ieee80211_rx_result ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); +void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); /* Mesh paths */ int mesh_nexthop_lookup(struct sk_buff *skb, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7c199987250..17bcad69428 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2616,6 +2616,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, cur_params.dot11MeshHWMPpreqMinInterval); NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, cur_params.dot11MeshHWMPnetDiameterTraversalTime); + NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, + cur_params.dot11MeshHWMPRootMode); nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); err = genlmsg_reply(msg, info); @@ -2726,6 +2728,10 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) dot11MeshHWMPnetDiameterTraversalTime, mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, + dot11MeshHWMPRootMode, mask, + NL80211_MESHCONF_HWMP_ROOTMODE, + nla_get_u8); /* Apply changes */ err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); -- cgit v1.2.3 From 264d9b7d8a629620c8de84c614910c3164e935f8 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Mon, 9 Nov 2009 23:46:58 +0000 Subject: mac80211: update copyrights to 2009 Signed-off-by: Rui Paulo Signed-off-by: Javier Cardona Reviewed-by: Andrey Yurovsky Tested-by: Brian Cavagnolo Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 2 +- net/mac80211/mesh.h | 2 +- net/mac80211/mesh_hwmp.c | 2 +- net/mac80211/mesh_pathtbl.c | 2 +- net/mac80211/mesh_plink.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 05955dc6b3d..bbd56b08789 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 open80211s Ltd. + * Copyright (c) 2008, 2009 open80211s Ltd. * Authors: Luis Carlos Cobo * Javier Cardona * diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 5ad6975bf28..bd0e1cbb9a1 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 open80211s Ltd. + * Copyright (c) 2008, 2009 open80211s Ltd. * Authors: Luis Carlos Cobo * Javier Cardona * diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 7483894a396..5c67e7b8790 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 open80211s Ltd. + * Copyright (c) 2008, 2009 open80211s Ltd. * Author: Luis Carlos Cobo * * This program is free software; you can redistribute it and/or modify diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 2cebdf52b7b..5399e7a9ec6 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 open80211s Ltd. + * Copyright (c) 2008, 2009 open80211s Ltd. * Author: Luis Carlos Cobo * * This program is free software; you can redistribute it and/or modify diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ec68d2046d2..f21329afdae 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 open80211s Ltd. + * Copyright (c) 2008, 2009 open80211s Ltd. * Author: Luis Carlos Cobo * * This program is free software; you can redistribute it and/or modify -- cgit v1.2.3 From a043897a314e8bcfc821d54fe4e591efed5936a3 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 11 Nov 2009 11:30:02 +0100 Subject: cfg80211: introduce nl80211_get_ifidx() ... which get's rid of three indentical cut-n-paste sections. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 76 ++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 17bcad69428..4dc139cdba5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -152,6 +152,26 @@ nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, }; +/* ifidx get helper */ +static int nl80211_get_ifidx(struct netlink_callback *cb) +{ + int res; + + res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, + nl80211_fam.attrbuf, nl80211_fam.maxattr, + nl80211_policy); + if (res) + return res; + + if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) + return -EINVAL; + + res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); + if (!res) + return -EINVAL; + return res; +} + /* IE validation */ static bool is_valid_ie_attr(const struct nlattr *attr) { @@ -1693,20 +1713,10 @@ static int nl80211_dump_station(struct sk_buff *skb, int sta_idx = cb->args[1]; int err; - if (!ifidx) { - err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, - nl80211_fam.attrbuf, nl80211_fam.maxattr, - nl80211_policy); - if (err) - return err; - - if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) - return -EINVAL; - - ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); - if (!ifidx) - return -EINVAL; - } + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; rtnl_lock(); @@ -2156,20 +2166,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, int path_idx = cb->args[1]; int err; - if (!ifidx) { - err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, - nl80211_fam.attrbuf, nl80211_fam.maxattr, - nl80211_policy); - if (err) - return err; - - if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) - return -EINVAL; - - ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); - if (!ifidx) - return -EINVAL; - } + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; rtnl_lock(); @@ -3198,21 +3198,11 @@ static int nl80211_dump_scan(struct sk_buff *skb, int start = cb->args[1], idx = 0; int err; - if (!ifidx) { - err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, - nl80211_fam.attrbuf, nl80211_fam.maxattr, - nl80211_policy); - if (err) - return err; - - if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) - return -EINVAL; - - ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); - if (!ifidx) - return -EINVAL; - cb->args[0] = ifidx; - } + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; + cb->args[0] = ifidx; dev = dev_get_by_index(sock_net(skb->sk), ifidx); if (!dev) -- cgit v1.2.3 From 61fa713c751683da915fa0c1aa502be85822c357 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 11 Nov 2009 12:25:40 +0100 Subject: cfg80211: return channel noise via survey API This patch implements the NL80211_CMD_GET_SURVEY command and an get_survey() ops that a driver can implement. The goal of this command is to allow a drivers to report channel survey data (e.g. channel noise, channel occupation). For now, only the mechanism to report back channel noise has been implemented. In future, there will either be a survey-trigger command --- or the existing scan-trigger command will be enhanced. This will allow user-space to request survey for arbitrary channels. Note: any driver that cannot report channel noise should not report any value at all, e.g. made-up -92 dBm. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- include/linux/nl80211.h | 34 ++++++++++++++++ include/net/cfg80211.h | 34 ++++++++++++++++ net/wireless/nl80211.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index d2f276de9ab..45db17f81aa 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -160,6 +160,11 @@ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * + * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation + * or noise level + * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to + * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) + * * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain * has been changed and provides details of the request information * that caused the change such as who initiated the regulatory request @@ -341,6 +346,9 @@ enum nl80211_commands { NL80211_CMD_SET_WIPHY_NETNS, + NL80211_CMD_GET_SURVEY, + NL80211_CMD_NEW_SURVEY_RESULTS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -586,6 +594,10 @@ enum nl80211_commands { * * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface * + * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of + * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute + * containing info as possible, see &enum survey_info. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -718,6 +730,8 @@ enum nl80211_attrs { NL80211_ATTR_4ADDR, + NL80211_ATTR_SURVEY_INFO, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1120,6 +1134,26 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_IBSS = 1<<8, }; +/** + * enum nl80211_survey_info - survey information + * + * These attribute types are used with %NL80211_ATTR_SURVEY_INFO + * when getting information about a survey. + * + * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved + * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel + * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) + */ +enum nl80211_survey_info { + __NL80211_SURVEY_INFO_INVALID, + NL80211_SURVEY_INFO_FREQUENCY, + NL80211_SURVEY_INFO_NOISE, + + /* keep last */ + __NL80211_SURVEY_INFO_AFTER_LAST, + NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 +}; + /** * enum nl80211_mntr_flags - monitor configuration flags * diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0e4c51fc63e..21710fc17ea 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -234,6 +234,35 @@ struct key_params { u32 cipher; }; +/** + * enum survey_info_flags - survey information flags + * + * Used by the driver to indicate which info in &struct survey_info + * it has filled in during the get_survey(). + */ +enum survey_info_flags { + SURVEY_INFO_NOISE_DBM = 1<<0, +}; + +/** + * struct survey_info - channel survey response + * + * Used by dump_survey() to report back per-channel survey information. + * + * @channel: the channel this survey record reports, mandatory + * @filled: bitflag of flags from &enum survey_info_flags + * @noise: channel noise in dBm. This and all following fields are + * optional + * + * This structure can later be expanded with things like + * channel duty cycle etc. + */ +struct survey_info { + struct ieee80211_channel *channel; + u32 filled; + s8 noise; +}; + /** * struct beacon_parameters - beacon parameters * @@ -944,6 +973,8 @@ struct cfg80211_bitrate_mask { * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting * functions to adjust rfkill hw state * + * @dump_survey: get site survey information. + * * @testmode_cmd: run a test mode command */ struct cfg80211_ops { @@ -1063,6 +1094,9 @@ struct cfg80211_ops { const u8 *peer, const struct cfg80211_bitrate_mask *mask); + int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, + int idx, struct survey_info *info); + /* some temporary stuff to finish wext */ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4dc139cdba5..5c8b3bfada4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3245,6 +3245,106 @@ static int nl80211_dump_scan(struct sk_buff *skb, return err; } +static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, + int flags, struct net_device *dev, + struct survey_info *survey) +{ + void *hdr; + struct nlattr *infoattr; + + /* Survey without a channel doesn't make sense */ + if (!survey->channel) + return -EINVAL; + + hdr = nl80211hdr_put(msg, pid, seq, flags, + NL80211_CMD_NEW_SURVEY_RESULTS); + if (!hdr) + return -ENOMEM; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + + infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); + if (!infoattr) + goto nla_put_failure; + + NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY, + survey->channel->center_freq); + if (survey->filled & SURVEY_INFO_NOISE_DBM) + NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, + survey->noise); + + nla_nest_end(msg, infoattr); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nl80211_dump_survey(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct survey_info survey; + struct cfg80211_registered_device *dev; + struct net_device *netdev; + int ifidx = cb->args[0]; + int survey_idx = cb->args[1]; + int res; + + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; + cb->args[0] = ifidx; + + rtnl_lock(); + + netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); + if (!netdev) { + res = -ENODEV; + goto out_rtnl; + } + + dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); + if (IS_ERR(dev)) { + res = PTR_ERR(dev); + goto out_rtnl; + } + + if (!dev->ops->dump_survey) { + res = -EOPNOTSUPP; + goto out_err; + } + + while (1) { + res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, + &survey); + if (res == -ENOENT) + break; + if (res) + goto out_err; + + if (nl80211_send_survey(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + netdev, + &survey) < 0) + goto out; + survey_idx++; + } + + out: + cb->args[1] = survey_idx; + res = skb->len; + out_err: + cfg80211_unlock_rdev(dev); + out_rtnl: + rtnl_unlock(); + + return res; +} + static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) { return auth_type <= NL80211_AUTHTYPE_MAX; @@ -4322,6 +4422,11 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_GET_SURVEY, + .policy = nl80211_policy, + .dumpit = nl80211_dump_survey, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", -- cgit v1.2.3 From f501dba4c4c5bda1b64c941997ab7ece1d503945 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Nov 2009 13:17:36 +0100 Subject: mac80211: fix broadcast frame handling for 4-addr AP VLANs Without this patch, broadcast frames from the station behind a 4-addr AP VLAN would be reflected back to the source. Fix this by checking the 4-addr flag before bridging multicast frames in the cell. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 006cf89df70..6bce97ee253 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1236,7 +1236,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) if ((sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && - (rx->flags & IEEE80211_RX_RA_MATCH)) { + (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) { if (is_multicast_ether_addr(ehdr->h_dest)) { /* * send multicast frames both to higher layers in -- cgit v1.2.3 From c258d2de972d1e391a3dec731e0801ed1cc85494 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Nov 2009 17:23:31 +0100 Subject: nl80211: only allow adding stations to running vlan interfaces Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5c8b3bfada4..37264d56bac 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1821,7 +1821,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) } /* - * Get vlan interface making sure it is on the right wiphy. + * Get vlan interface making sure it is running and on the right wiphy. */ static int get_vlan(struct genl_info *info, struct cfg80211_registered_device *rdev, @@ -1839,6 +1839,8 @@ static int get_vlan(struct genl_info *info, return -EINVAL; if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) return -EINVAL; + if (!netif_running(*vlan)) + return -ENETDOWN; } return 0; } -- cgit v1.2.3 From bee7ca9ec03a26676ea2b1c28dc4039348eff3e1 Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Tue, 10 Nov 2009 09:51:18 +0000 Subject: net: TCP_MSS_DEFAULT, TCP_MSS_DESIRED Define two symbols needed in both kernel and user space. Remove old (somewhat incorrect) kernel variant that wasn't used in most cases. Default should apply to both RMSS and SMSS (RFC2581). Replace numeric constants with defined symbols. Stand-alone patch, originally developed for TCPCT. Signed-off-by: William.Allen.Simpson@gmail.com Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/tcp.h | 6 ++++++ include/net/tcp.h | 3 --- net/ipv4/tcp_input.c | 4 ++-- net/ipv4/tcp_ipv4.c | 6 +++--- net/ipv4/tcp_minisocks.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index eeecb8547a2..32d7d77b4a0 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -81,6 +81,12 @@ enum { TCP_DATA_OFFSET = __cpu_to_be32(0xF0000000) }; +/* + * TCP general constants + */ +#define TCP_MSS_DEFAULT 536U /* IPv4 (RFC1122, RFC2581) */ +#define TCP_MSS_DESIRED 1220U /* IPv6 (tunneled), EDNS0 (RFC3226) */ + /* TCP socket options */ #define TCP_NODELAY 1 /* Turn off Nagle's algorithm. */ #define TCP_MAXSEG 2 /* Limit MSS */ diff --git a/include/net/tcp.h b/include/net/tcp.h index bf20f88fd03..325bfcf5c93 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -62,9 +62,6 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); /* Minimal accepted MSS. It is (60+60+8) - (20+20). */ #define TCP_MIN_MSS 88U -/* Minimal RCV_MSS. */ -#define TCP_MIN_RCVMSS 536U - /* The least MTU to use for probing */ #define TCP_BASE_MSS 512 diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index be0c5bf7bfc..cc306ac6eb5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -140,7 +140,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) * "len" is invariant segment length, including TCP header. */ len += skb->data - skb_transport_header(skb); - if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) || + if (len >= TCP_MSS_DEFAULT + sizeof(struct tcphdr) || /* If PSH is not set, packet should be * full sized, provided peer TCP is not badly broken. * This observation (if it is correct 8)) allows @@ -411,7 +411,7 @@ void tcp_initialize_rcv_mss(struct sock *sk) unsigned int hint = min_t(unsigned int, tp->advmss, tp->mss_cache); hint = min(hint, tp->rcv_wnd / 2); - hint = min(hint, TCP_MIN_RCVMSS); + hint = min(hint, TCP_MSS_DEFAULT); hint = max(hint, TCP_MIN_MSS); inet_csk(sk)->icsk_ack.rcv_mss = hint; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 657ae334f12..cf7f2086e6e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -217,7 +217,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (inet->opt) inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen; - tp->rx_opt.mss_clamp = 536; + tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT; /* Socket identity is still unknown (sport may be zero). * However we set state to SYN-SENT and not releasing socket @@ -1268,7 +1268,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_free; tcp_clear_options(&tmp_opt); - tmp_opt.mss_clamp = 536; + tmp_opt.mss_clamp = TCP_MSS_DEFAULT; tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; tcp_parse_options(skb, &tmp_opt, 0, dst); @@ -1815,7 +1815,7 @@ static int tcp_v4_init_sock(struct sock *sk) */ tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_clamp = ~0; - tp->mss_cache = 536; + tp->mss_cache = TCP_MSS_DEFAULT; tp->reordering = sysctl_tcp_reordering; icsk->icsk_ca_ops = &tcp_init_congestion_ops; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index a9d34e224cb..4be22280e6b 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -476,7 +476,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, if (newtp->af_specific->md5_lookup(sk, newsk)) newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; #endif - if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len) + if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len) newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; newtp->rx_opt.mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 696a22f034e..de709091b26 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1851,7 +1851,7 @@ static int tcp_v6_init_sock(struct sock *sk) */ tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_clamp = ~0; - tp->mss_cache = 536; + tp->mss_cache = TCP_MSS_DEFAULT; tp->reordering = sysctl_tcp_reordering; -- cgit v1.2.3 From ce81b76a39835a721cd168e0c0bcfe7132f1f66b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Nov 2009 17:34:30 +0000 Subject: ipv6: use RCU to walk list of network devices No longer need read_lock(&dev_base_lock), use RCU instead. We also can avoid taking references on inet6_dev structs. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 10 ++++++++++ net/ipv6/anycast.c | 29 +++++++++++++-------------- net/ipv6/mcast.c | 51 +++++++++++++++++++++-------------------------- 3 files changed, 47 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8b266390b9e..61425d0c612 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1114,6 +1114,16 @@ static inline struct net_device *next_net_device(struct net_device *dev) return lh == &net->dev_base_head ? NULL : net_device_entry(lh); } +static inline struct net_device *next_net_device_rcu(struct net_device *dev) +{ + struct list_head *lh; + struct net *net; + + net = dev_net(dev); + lh = rcu_dereference(dev->dev_list.next); + return lh == &net->dev_base_head ? NULL : net_device_entry(lh); +} + static inline struct net_device *first_net_device(struct net *net) { return list_empty(&net->dev_base_head) ? NULL : diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 2f00ca83f04..f1c74c8ef9d 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -431,9 +431,9 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) struct net *net = seq_file_net(seq); state->idev = NULL; - for_each_netdev(net, state->dev) { + for_each_netdev_rcu(net, state->dev) { struct inet6_dev *idev; - idev = in6_dev_get(state->dev); + idev = __in6_dev_get(state->dev); if (!idev) continue; read_lock_bh(&idev->lock); @@ -443,7 +443,6 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) break; } read_unlock_bh(&idev->lock); - in6_dev_put(idev); } return im; } @@ -454,16 +453,15 @@ static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im im = im->aca_next; while (!im) { - if (likely(state->idev != NULL)) { + if (likely(state->idev != NULL)) read_unlock_bh(&state->idev->lock); - in6_dev_put(state->idev); - } - state->dev = next_net_device(state->dev); + + state->dev = next_net_device_rcu(state->dev); if (!state->dev) { state->idev = NULL; break; } - state->idev = in6_dev_get(state->dev); + state->idev = __in6_dev_get(state->dev); if (!state->idev) continue; read_lock_bh(&state->idev->lock); @@ -482,29 +480,30 @@ static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos) } static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) + __acquires(RCU) { - read_lock(&dev_base_lock); + rcu_read_lock(); return ac6_get_idx(seq, *pos); } static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct ifacaddr6 *im; - im = ac6_get_next(seq, v); + struct ifacaddr6 *im = ac6_get_next(seq, v); + ++*pos; return im; } static void ac6_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) + __releases(RCU) { struct ac6_iter_state *state = ac6_seq_private(seq); + if (likely(state->idev != NULL)) { read_unlock_bh(&state->idev->lock); - in6_dev_put(state->idev); + state->idev = NULL; } - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int ac6_seq_show(struct seq_file *seq, void *v) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f9fcf690bd5..1f9c44442e6 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2375,9 +2375,9 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) struct net *net = seq_file_net(seq); state->idev = NULL; - for_each_netdev(net, state->dev) { + for_each_netdev_rcu(net, state->dev) { struct inet6_dev *idev; - idev = in6_dev_get(state->dev); + idev = __in6_dev_get(state->dev); if (!idev) continue; read_lock_bh(&idev->lock); @@ -2387,7 +2387,6 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) break; } read_unlock_bh(&idev->lock); - in6_dev_put(idev); } return im; } @@ -2398,16 +2397,15 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr im = im->next; while (!im) { - if (likely(state->idev != NULL)) { + if (likely(state->idev != NULL)) read_unlock_bh(&state->idev->lock); - in6_dev_put(state->idev); - } - state->dev = next_net_device(state->dev); + + state->dev = next_net_device_rcu(state->dev); if (!state->dev) { state->idev = NULL; break; } - state->idev = in6_dev_get(state->dev); + state->idev = __in6_dev_get(state->dev); if (!state->idev) continue; read_lock_bh(&state->idev->lock); @@ -2426,31 +2424,31 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos) } static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) + __acquires(RCU) { - read_lock(&dev_base_lock); + rcu_read_lock(); return igmp6_mc_get_idx(seq, *pos); } static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct ifmcaddr6 *im; - im = igmp6_mc_get_next(seq, v); + struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v); + ++*pos; return im; } static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) + __releases(RCU) { struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); + if (likely(state->idev != NULL)) { read_unlock_bh(&state->idev->lock); - in6_dev_put(state->idev); state->idev = NULL; } state->dev = NULL; - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int igmp6_mc_seq_show(struct seq_file *seq, void *v) @@ -2507,9 +2505,9 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) state->idev = NULL; state->im = NULL; - for_each_netdev(net, state->dev) { + for_each_netdev_rcu(net, state->dev) { struct inet6_dev *idev; - idev = in6_dev_get(state->dev); + idev = __in6_dev_get(state->dev); if (unlikely(idev == NULL)) continue; read_lock_bh(&idev->lock); @@ -2525,7 +2523,6 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) spin_unlock_bh(&im->mca_lock); } read_unlock_bh(&idev->lock); - in6_dev_put(idev); } return psf; } @@ -2539,16 +2536,15 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s spin_unlock_bh(&state->im->mca_lock); state->im = state->im->next; while (!state->im) { - if (likely(state->idev != NULL)) { + if (likely(state->idev != NULL)) read_unlock_bh(&state->idev->lock); - in6_dev_put(state->idev); - } - state->dev = next_net_device(state->dev); + + state->dev = next_net_device_rcu(state->dev); if (!state->dev) { state->idev = NULL; goto out; } - state->idev = in6_dev_get(state->dev); + state->idev = __in6_dev_get(state->dev); if (!state->idev) continue; read_lock_bh(&state->idev->lock); @@ -2573,9 +2569,9 @@ static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos) } static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) + __acquires(RCU) { - read_lock(&dev_base_lock); + rcu_read_lock(); return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } @@ -2591,7 +2587,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) + __releases(RCU) { struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); if (likely(state->im != NULL)) { @@ -2600,11 +2596,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) } if (likely(state->idev != NULL)) { read_unlock_bh(&state->idev->lock); - in6_dev_put(state->idev); state->idev = NULL; } state->dev = NULL; - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) -- cgit v1.2.3 From 6baff15037693c057e3047da02c460c7e7b346c2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Nov 2009 17:48:52 +0000 Subject: igmp: Use next_net_device_rcu() We need to use next_det_device_rcu() in RCU protected section. We also can avoid in_dev_get()/in_dev_put() overhead (code size mainly) in rcu_read_lock() sections. Signed-off-by: Eric Dumazet Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index bd24f6560a4..6110c6d6e61 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2313,7 +2313,8 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) state->in_dev = NULL; for_each_netdev_rcu(net, state->dev) { struct in_device *in_dev; - in_dev = in_dev_get(state->dev); + + in_dev = __in_dev_get_rcu(state->dev); if (!in_dev) continue; read_lock(&in_dev->mc_list_lock); @@ -2323,7 +2324,6 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) break; } read_unlock(&in_dev->mc_list_lock); - in_dev_put(in_dev); } return im; } @@ -2333,16 +2333,15 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); im = im->next; while (!im) { - if (likely(state->in_dev != NULL)) { + if (likely(state->in_dev != NULL)) read_unlock(&state->in_dev->mc_list_lock); - in_dev_put(state->in_dev); - } - state->dev = next_net_device(state->dev); + + state->dev = next_net_device_rcu(state->dev); if (!state->dev) { state->in_dev = NULL; break; } - state->in_dev = in_dev_get(state->dev); + state->in_dev = __in_dev_get_rcu(state->dev); if (!state->in_dev) continue; read_lock(&state->in_dev->mc_list_lock); @@ -2384,7 +2383,6 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v) struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); if (likely(state->in_dev != NULL)) { read_unlock(&state->in_dev->mc_list_lock); - in_dev_put(state->in_dev); state->in_dev = NULL; } state->dev = NULL; @@ -2464,7 +2462,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) state->im = NULL; for_each_netdev_rcu(net, state->dev) { struct in_device *idev; - idev = in_dev_get(state->dev); + idev = __in_dev_get_rcu(state->dev); if (unlikely(idev == NULL)) continue; read_lock(&idev->mc_list_lock); @@ -2480,7 +2478,6 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) spin_unlock_bh(&im->lock); } read_unlock(&idev->mc_list_lock); - in_dev_put(idev); } return psf; } @@ -2494,16 +2491,15 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l spin_unlock_bh(&state->im->lock); state->im = state->im->next; while (!state->im) { - if (likely(state->idev != NULL)) { + if (likely(state->idev != NULL)) read_unlock(&state->idev->mc_list_lock); - in_dev_put(state->idev); - } - state->dev = next_net_device(state->dev); + + state->dev = next_net_device_rcu(state->dev); if (!state->dev) { state->idev = NULL; goto out; } - state->idev = in_dev_get(state->dev); + state->idev = __in_dev_get_rcu(state->dev); if (!state->idev) continue; read_lock(&state->idev->mc_list_lock); @@ -2555,7 +2551,6 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) } if (likely(state->idev != NULL)) { read_unlock(&state->idev->mc_list_lock); - in_dev_put(state->idev); state->idev = NULL; } state->dev = NULL; -- cgit v1.2.3 From eec4df9885f7822cdeca82577a25cac4598fa7cf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 12 Nov 2009 07:44:25 +0000 Subject: ipv4: speedup inet_dump_ifaddr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stephen Hemminger a écrit : > On Thu, 12 Nov 2009 15:11:36 +0100 > Eric Dumazet wrote: > >> When handling large number of netdevices, inet_dump_ifaddr() >> is very slow because it has O(N^2) complexity. >> >> Instead of scanning one single list, we can use the NETDEV_HASHENTRIES >> sub lists of the dev_index hash table, and RCU lookups. >> >> Signed-off-by: Eric Dumazet > > You might be able to make RCU critical section smaller by moving > it into loop. > Indeed. But we dump at most one skb (<= 8192 bytes ?), so rcu_read_lock holding time is small, unless we meet many netdevices without addresses. I wonder if its really common... Thanks [PATCH net-next-2.6] ipv4: speedup inet_dump_ifaddr() When handling large number of netdevices, inet_dump_ifaddr() is very slow because it has O(N2) complexity. Instead of scanning one single list, we can use the NETDEV_HASHENTRIES sub lists of the dev_index hash table, and RCU lookups. Signed-off-by: Eric Dumazet Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 61 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c2045f9615d..7620382058a 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1174,39 +1174,54 @@ nla_put_failure: static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); - int idx, ip_idx; + int h, s_h; + int idx, s_idx; + int ip_idx, s_ip_idx; struct net_device *dev; struct in_device *in_dev; struct in_ifaddr *ifa; - int s_ip_idx, s_idx = cb->args[0]; + struct hlist_head *head; + struct hlist_node *node; - s_ip_idx = ip_idx = cb->args[1]; - idx = 0; - for_each_netdev(net, dev) { - if (idx < s_idx) - goto cont; - if (idx > s_idx) - s_ip_idx = 0; - in_dev = __in_dev_get_rtnl(dev); - if (!in_dev) - goto cont; + s_h = cb->args[0]; + s_idx = idx = cb->args[1]; + s_ip_idx = ip_idx = cb->args[2]; - for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; - ifa = ifa->ifa_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, + for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { + idx = 0; + head = &net->dev_index_head[h]; + rcu_read_lock(); + hlist_for_each_entry_rcu(dev, node, head, index_hlist) { + if (idx < s_idx) + goto cont; + if (idx > s_idx) + s_ip_idx = 0; + in_dev = __in_dev_get_rcu(dev); + if (!in_dev) + goto cont; + + for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; + ifa = ifa->ifa_next, ip_idx++) { + if (ip_idx < s_ip_idx) + continue; + if (inet_fill_ifaddr(skb, ifa, + NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, - RTM_NEWADDR, NLM_F_MULTI) <= 0) - goto done; - } + RTM_NEWADDR, NLM_F_MULTI) <= 0) { + rcu_read_unlock(); + goto done; + } + } cont: - idx++; + idx++; + } + rcu_read_unlock(); } done: - cb->args[0] = idx; - cb->args[1] = ip_idx; + cb->args[0] = h; + cb->args[1] = idx; + cb->args[2] = ip_idx; return skb->len; } -- cgit v1.2.3 From 234b27c3fd58fc0e15c04dd0fbf4337fac9c2a06 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 12 Nov 2009 04:11:50 +0000 Subject: ipv6: speedup inet6_dump_addr() When handling large number of netdevices, inet6_dump_addr() is very slow because it has O(N^2) complexity. Instead of scanning one single list, we can use the NETDEV_HASHENTRIES sub lists of the dev_index hash table, and RCU lookups. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 171 +++++++++++++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 74 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9ff8ab9a154..522bdc77206 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3481,91 +3481,114 @@ enum addr_type_t ANYCAST_ADDR, }; +/* called with rcu_read_lock() */ +static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, + struct netlink_callback *cb, enum addr_type_t type, + int s_ip_idx, int *p_ip_idx) +{ + struct inet6_ifaddr *ifa; + struct ifmcaddr6 *ifmca; + struct ifacaddr6 *ifaca; + int err = 1; + int ip_idx = *p_ip_idx; + + read_lock_bh(&idev->lock); + switch (type) { + case UNICAST_ADDR: + /* unicast address incl. temp addr */ + for (ifa = idev->addr_list; ifa; + ifa = ifa->if_next, ip_idx++) { + if (ip_idx < s_ip_idx) + continue; + err = inet6_fill_ifaddr(skb, ifa, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_NEWADDR, + NLM_F_MULTI); + if (err <= 0) + break; + } + break; + case MULTICAST_ADDR: + /* multicast address */ + for (ifmca = idev->mc_list; ifmca; + ifmca = ifmca->next, ip_idx++) { + if (ip_idx < s_ip_idx) + continue; + err = inet6_fill_ifmcaddr(skb, ifmca, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_GETMULTICAST, + NLM_F_MULTI); + if (err <= 0) + break; + } + break; + case ANYCAST_ADDR: + /* anycast address */ + for (ifaca = idev->ac_list; ifaca; + ifaca = ifaca->aca_next, ip_idx++) { + if (ip_idx < s_ip_idx) + continue; + err = inet6_fill_ifacaddr(skb, ifaca, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_GETANYCAST, + NLM_F_MULTI); + if (err <= 0) + break; + } + break; + default: + break; + } + read_unlock_bh(&idev->lock); + *p_ip_idx = ip_idx; + return err; +} + static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, enum addr_type_t type) { + struct net *net = sock_net(skb->sk); + int h, s_h; int idx, ip_idx; int s_idx, s_ip_idx; - int err = 1; struct net_device *dev; - struct inet6_dev *idev = NULL; - struct inet6_ifaddr *ifa; - struct ifmcaddr6 *ifmca; - struct ifacaddr6 *ifaca; - struct net *net = sock_net(skb->sk); + struct inet6_dev *idev; + struct hlist_head *head; + struct hlist_node *node; - s_idx = cb->args[0]; - s_ip_idx = ip_idx = cb->args[1]; + s_h = cb->args[0]; + s_idx = idx = cb->args[1]; + s_ip_idx = ip_idx = cb->args[2]; - idx = 0; - for_each_netdev(net, dev) { - if (idx < s_idx) - goto cont; - if (idx > s_idx) - s_ip_idx = 0; - ip_idx = 0; - if ((idev = in6_dev_get(dev)) == NULL) - goto cont; - read_lock_bh(&idev->lock); - switch (type) { - case UNICAST_ADDR: - /* unicast address incl. temp addr */ - for (ifa = idev->addr_list; ifa; - ifa = ifa->if_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - err = inet6_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - RTM_NEWADDR, - NLM_F_MULTI); - if (err <= 0) - break; - } - break; - case MULTICAST_ADDR: - /* multicast address */ - for (ifmca = idev->mc_list; ifmca; - ifmca = ifmca->next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - err = inet6_fill_ifmcaddr(skb, ifmca, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - RTM_GETMULTICAST, - NLM_F_MULTI); - if (err <= 0) - break; - } - break; - case ANYCAST_ADDR: - /* anycast address */ - for (ifaca = idev->ac_list; ifaca; - ifaca = ifaca->aca_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - err = inet6_fill_ifacaddr(skb, ifaca, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - RTM_GETANYCAST, - NLM_F_MULTI); - if (err <= 0) - break; - } - break; - default: - break; - } - read_unlock_bh(&idev->lock); - in6_dev_put(idev); + rcu_read_lock(); + for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { + idx = 0; + head = &net->dev_index_head[h]; + hlist_for_each_entry_rcu(dev, node, head, index_hlist) { + if (idx < s_idx) + goto cont; + if (idx > s_idx) + s_ip_idx = 0; + ip_idx = 0; + if ((idev = __in6_dev_get(dev)) == NULL) + goto cont; - if (err <= 0) - break; + if (in6_dump_addrs(idev, skb, cb, type, + s_ip_idx, &ip_idx) <= 0) + goto done; cont: - idx++; + idx++; + } } - cb->args[0] = idx; - cb->args[1] = ip_idx; +done: + rcu_read_unlock(); + cb->args[0] = h; + cb->args[1] = idx; + cb->args[2] = ip_idx; + return skb->len; } -- cgit v1.2.3 From 2c1409a0a2b88585ec0c03f1de0aafa178c56313 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 12 Nov 2009 09:33:09 +0000 Subject: inetpeer: Optimize inet_getid() While investigating for network latencies, I found inet_getid() was a contention point for some workloads, as inet_peer_idlock is shared by all inet_getid() users regardless of peers. One way to fix this is to make ip_id_count an atomic_t instead of __u16, and use atomic_add_return(). In order to keep sizeof(struct inet_peer) = 64 on 64bit arches tcp_ts_stamp is also converted to __u32 instead of "unsigned long". Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inetpeer.h | 16 +++++----------- net/ipv4/inetpeer.c | 5 +---- net/ipv4/route.c | 2 +- net/ipv4/tcp_ipv4.c | 16 ++++++++-------- 4 files changed, 15 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 35ad7b93046..87b1df0d4d8 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -17,15 +17,15 @@ struct inet_peer { /* group together avl_left,avl_right,v4daddr to speedup lookups */ struct inet_peer *avl_left, *avl_right; __be32 v4daddr; /* peer's address */ - __u16 avl_height; - __u16 ip_id_count; /* IP ID for the next packet */ + __u32 avl_height; struct list_head unused; __u32 dtime; /* the time of last use of not * referenced entries */ atomic_t refcnt; atomic_t rid; /* Frag reception counter */ + atomic_t ip_id_count; /* IP ID for the next packet */ __u32 tcp_ts; - unsigned long tcp_ts_stamp; + __u32 tcp_ts_stamp; }; void inet_initpeers(void) __init; @@ -36,17 +36,11 @@ struct inet_peer *inet_getpeer(__be32 daddr, int create); /* can be called from BH context or outside */ extern void inet_putpeer(struct inet_peer *p); -extern spinlock_t inet_peer_idlock; /* can be called with or without local BH being disabled */ static inline __u16 inet_getid(struct inet_peer *p, int more) { - __u16 id; - - spin_lock_bh(&inet_peer_idlock); - id = p->ip_id_count; - p->ip_id_count += 1 + more; - spin_unlock_bh(&inet_peer_idlock); - return id; + more++; + return atomic_add_return(more, &p->ip_id_count) - more; } #endif /* _NET_INETPEER_H */ diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index b1fbe18feb5..6bcfe52a9c8 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -67,9 +67,6 @@ * ip_id_count: idlock */ -/* Exported for inet_getid inline function. */ -DEFINE_SPINLOCK(inet_peer_idlock); - static struct kmem_cache *peer_cachep __read_mostly; #define node_height(x) x->avl_height @@ -390,7 +387,7 @@ struct inet_peer *inet_getpeer(__be32 daddr, int create) n->v4daddr = daddr; atomic_set(&n->refcnt, 1); atomic_set(&n->rid, 0); - n->ip_id_count = secure_ip_id(daddr); + atomic_set(&n->ip_id_count, secure_ip_id(daddr)); n->tcp_ts_stamp = 0; write_lock_bh(&peer_pool_lock); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ff258b57680..4284ceef794 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2852,7 +2852,7 @@ static int rt_fill_info(struct net *net, error = rt->u.dst.error; expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; if (rt->peer) { - id = rt->peer->ip_id_count; + id = atomic_read(&rt->peer->ip_id_count) & 0xffff; if (rt->peer->tcp_ts_stamp) { ts = rt->peer->tcp_ts; tsage = get_seconds() - rt->peer->tcp_ts_stamp; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cf7f2086e6e..df18ce04f41 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -204,7 +204,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) * when trying new connection. */ if (peer != NULL && - peer->tcp_ts_stamp + TCP_PAWS_MSL >= get_seconds()) { + (u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) { tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; tp->rx_opt.ts_recent = peer->tcp_ts; } @@ -1308,7 +1308,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_death_row.sysctl_tw_recycle && (peer = rt_get_peer((struct rtable *)dst)) != NULL && peer->v4daddr == saddr) { - if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL && + if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); @@ -1727,9 +1727,9 @@ int tcp_v4_remember_stamp(struct sock *sk) if (peer) { if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 || - (peer->tcp_ts_stamp + TCP_PAWS_MSL < get_seconds() && - peer->tcp_ts_stamp <= tp->rx_opt.ts_recent_stamp)) { - peer->tcp_ts_stamp = tp->rx_opt.ts_recent_stamp; + ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && + peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) { + peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp; peer->tcp_ts = tp->rx_opt.ts_recent; } if (release_it) @@ -1748,9 +1748,9 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || - (peer->tcp_ts_stamp + TCP_PAWS_MSL < get_seconds() && - peer->tcp_ts_stamp <= tcptw->tw_ts_recent_stamp)) { - peer->tcp_ts_stamp = tcptw->tw_ts_recent_stamp; + ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && + peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { + peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; peer->tcp_ts = tcptw->tw_ts_recent; } inet_putpeer(peer); -- cgit v1.2.3 From b7c2aecc0747f5c86a1959bce6a7ce8170a556b0 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Thu, 12 Nov 2009 21:46:27 +0000 Subject: iucv: add work_queue cleanup for suspend If iucv_work_queue is not empty during kernel freeze, a kernel panic occurs. This suspend-patch adds flushing of the work queue for pending connection requests and severing of remaining pending connections. Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/iucv/iucv.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 3973d0e61e5..3b1f5f5f8de 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -1768,7 +1768,6 @@ static void iucv_tasklet_fn(unsigned long ignored) */ static void iucv_work_fn(struct work_struct *work) { - typedef void iucv_irq_fn(struct iucv_irq_data *); LIST_HEAD(work_queue); struct iucv_irq_list *p, *n; @@ -1878,14 +1877,25 @@ int iucv_path_table_empty(void) static int iucv_pm_freeze(struct device *dev) { int cpu; + struct iucv_irq_list *p, *n; int rc = 0; #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "iucv_pm_freeze\n"); #endif + if (iucv_pm_state != IUCV_PM_FREEZING) { + for_each_cpu_mask_nr(cpu, iucv_irq_cpumask) + smp_call_function_single(cpu, iucv_block_cpu_almost, + NULL, 1); + cancel_work_sync(&iucv_work); + list_for_each_entry_safe(p, n, &iucv_work_queue, list) { + list_del_init(&p->list); + iucv_sever_pathid(p->data.ippathid, + iucv_error_no_listener); + kfree(p); + } + } iucv_pm_state = IUCV_PM_FREEZING; - for_each_cpu_mask_nr(cpu, iucv_irq_cpumask) - smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1); if (dev->driver && dev->driver->pm && dev->driver->pm->freeze) rc = dev->driver->pm->freeze(dev); if (iucv_path_table_empty()) -- cgit v1.2.3 From 7ed0132f232b11ae58b6d868e8d7ada9dfa066d7 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Fri, 13 Nov 2009 05:01:18 +0000 Subject: Phonet: put protocols array under RCU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/af_phonet.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 8d3a55b4a30..ed65da251b6 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -35,7 +35,6 @@ /* Transport protocol registration */ static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly; -static DEFINE_SPINLOCK(proto_tab_lock); static struct phonet_protocol *phonet_proto_get(int protocol) { @@ -44,11 +43,11 @@ static struct phonet_protocol *phonet_proto_get(int protocol) if (protocol >= PHONET_NPROTO) return NULL; - spin_lock(&proto_tab_lock); + rcu_read_lock(); pp = proto_tab[protocol]; if (pp && !try_module_get(pp->prot->owner)) pp = NULL; - spin_unlock(&proto_tab_lock); + rcu_read_unlock(); return pp; } @@ -439,6 +438,8 @@ static struct packet_type phonet_packet_type __read_mostly = { .func = phonet_rcv, }; +static DEFINE_MUTEX(proto_tab_lock); + int __init_or_module phonet_proto_register(int protocol, struct phonet_protocol *pp) { @@ -451,12 +452,12 @@ int __init_or_module phonet_proto_register(int protocol, if (err) return err; - spin_lock(&proto_tab_lock); + mutex_lock(&proto_tab_lock); if (proto_tab[protocol]) err = -EBUSY; else - proto_tab[protocol] = pp; - spin_unlock(&proto_tab_lock); + rcu_assign_pointer(proto_tab[protocol], pp); + mutex_unlock(&proto_tab_lock); return err; } @@ -464,10 +465,11 @@ EXPORT_SYMBOL(phonet_proto_register); void phonet_proto_unregister(int protocol, struct phonet_protocol *pp) { - spin_lock(&proto_tab_lock); + mutex_lock(&proto_tab_lock); BUG_ON(proto_tab[protocol] != pp); - proto_tab[protocol] = NULL; - spin_unlock(&proto_tab_lock); + rcu_assign_pointer(proto_tab[protocol], NULL); + mutex_unlock(&proto_tab_lock); + synchronize_rcu(); proto_unregister(pp->prot); } EXPORT_SYMBOL(phonet_proto_unregister); -- cgit v1.2.3 From 888801357f240daee5d310327867d834bc05183b Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Fri, 13 Nov 2009 05:01:19 +0000 Subject: Phonet: convert routing table to RCU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/pn_dev.c | 59 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 6d64fda1afc..3287f8f0b5c 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -34,7 +34,7 @@ #include struct phonet_routes { - spinlock_t lock; + struct mutex lock; struct net_device *table[64]; }; @@ -248,17 +248,22 @@ static void phonet_route_autodel(struct net_device *dev) /* Remove left-over Phonet routes */ bitmap_zero(deleted, 64); - spin_lock_bh(&pnn->routes.lock); + mutex_lock(&pnn->routes.lock); for (i = 0; i < 64; i++) if (dev == pnn->routes.table[i]) { + rcu_assign_pointer(pnn->routes.table[i], NULL); set_bit(i, deleted); - pnn->routes.table[i] = NULL; - dev_put(dev); } - spin_unlock_bh(&pnn->routes.lock); + mutex_unlock(&pnn->routes.lock); + + if (bitmap_empty(deleted, 64)) + return; /* short-circuit RCU */ + synchronize_rcu(); for (i = find_first_bit(deleted, 64); i < 64; - i = find_next_bit(deleted, 64, i + 1)) + i = find_next_bit(deleted, 64, i + 1)) { rtm_phonet_notify(RTM_DELROUTE, dev, i); + dev_put(dev); + } } /* notify Phonet of device events */ @@ -300,7 +305,7 @@ static int phonet_init_net(struct net *net) INIT_LIST_HEAD(&pnn->pndevs.list); spin_lock_init(&pnn->pndevs.lock); - spin_lock_init(&pnn->routes.lock); + mutex_init(&pnn->routes.lock); net_assign_generic(net, phonet_net_id, pnn); return 0; } @@ -361,13 +366,13 @@ int phonet_route_add(struct net_device *dev, u8 daddr) int err = -EEXIST; daddr = daddr >> 2; - spin_lock_bh(&routes->lock); + mutex_lock(&routes->lock); if (routes->table[daddr] == NULL) { - routes->table[daddr] = dev; + rcu_assign_pointer(routes->table[daddr], dev); dev_hold(dev); err = 0; } - spin_unlock_bh(&routes->lock); + mutex_unlock(&routes->lock); return err; } @@ -375,17 +380,20 @@ int phonet_route_del(struct net_device *dev, u8 daddr) { struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id); struct phonet_routes *routes = &pnn->routes; - int err = -ENOENT; daddr = daddr >> 2; - spin_lock_bh(&routes->lock); - if (dev == routes->table[daddr]) { - routes->table[daddr] = NULL; - dev_put(dev); - err = 0; - } - spin_unlock_bh(&routes->lock); - return err; + mutex_lock(&routes->lock); + if (dev == routes->table[daddr]) + rcu_assign_pointer(routes->table[daddr], NULL); + else + dev = NULL; + mutex_unlock(&routes->lock); + + if (!dev) + return -ENOENT; + synchronize_rcu(); + dev_put(dev); + return 0; } struct net_device *phonet_route_get(struct net *net, u8 daddr) @@ -397,9 +405,9 @@ struct net_device *phonet_route_get(struct net *net, u8 daddr) ASSERT_RTNL(); /* no need to hold the device */ daddr >>= 2; - spin_lock_bh(&routes->lock); - dev = routes->table[daddr]; - spin_unlock_bh(&routes->lock); + rcu_read_lock(); + dev = rcu_dereference(routes->table[daddr]); + rcu_read_unlock(); return dev; } @@ -409,11 +417,12 @@ struct net_device *phonet_route_output(struct net *net, u8 daddr) struct phonet_routes *routes = &pnn->routes; struct net_device *dev; - spin_lock_bh(&routes->lock); - dev = routes->table[daddr >> 2]; + daddr >>= 2; + rcu_read_lock(); + dev = rcu_dereference(routes->table[daddr]); if (dev) dev_hold(dev); - spin_unlock_bh(&routes->lock); + rcu_read_unlock(); if (!dev) dev = phonet_device_get(net); /* Default route */ -- cgit v1.2.3 From ed04642f753b1240fc65c2978b7365e93209972a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 13 Nov 2009 21:54:04 +0000 Subject: net: check the return value of ndo_select_queue() Check the return value of ndo_select_queue(). If the value isn't smaller than the real_num_tx_queues, print a warning message, and reset it to zero. Signed-off-by: Changli Gao Signed-off-by: Eric Dumazet ---- Signed-off-by: David S. Miller --- net/core/dev.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 548340b5729..32045df1da5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1848,6 +1848,20 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb) } EXPORT_SYMBOL(skb_tx_hash); +static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index) +{ + if (unlikely(queue_index >= dev->real_num_tx_queues)) { + if (net_ratelimit()) { + WARN(1, "%s selects TX queue %d, but " + "real number of TX queues is %d\n", + dev->name, queue_index, + dev->real_num_tx_queues); + } + return 0; + } + return queue_index; +} + static struct netdev_queue *dev_pick_tx(struct net_device *dev, struct sk_buff *skb) { @@ -1861,6 +1875,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev, if (ops->ndo_select_queue) { queue_index = ops->ndo_select_queue(dev, skb); + queue_index = dev_cap_txqueue(dev, queue_index); } else { queue_index = 0; if (dev->real_num_tx_queues > 1) -- cgit v1.2.3 From 9a1654ba0b50402a6bd03c7b0fe9b0200a5ea7b1 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Sun, 15 Nov 2009 07:20:12 +0000 Subject: net: Optimize hard_start_xmit() return checking Recent changes in the TX error propagation require additional checking and masking of values returned from hard_start_xmit(), mainly to separate cases where skb was consumed. This aim can be simplified by changing the order of NETDEV_TX and NET_XMIT codes, because the latter are treated similarly to negative (ERRNO) values. After this change much simpler dev_xmit_complete() is also used in sch_direct_xmit(), so it is moved to netdevice.h. Additionally NET_RX definitions in netdevice.h are moved up from between TX codes to avoid confusion while reading the TX comment. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- include/linux/netdevice.h | 42 ++++++++++++++++++++++++++++++------------ net/core/dev.c | 17 ----------------- net/sched/sch_generic.c | 23 +++++------------------ 3 files changed, 35 insertions(+), 47 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 61425d0c612..7043f85e643 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -63,6 +63,10 @@ struct wireless_dev; #define HAVE_FREE_NETDEV /* free_netdev() */ #define HAVE_NETDEV_PRIV /* netdev_priv() */ +/* Backlog congestion levels */ +#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ +#define NET_RX_DROP 1 /* packet dropped */ + /* * Transmit return codes: transmit return codes originate from three different * namespaces: @@ -82,14 +86,10 @@ struct wireless_dev; /* qdisc ->enqueue() return codes. */ #define NET_XMIT_SUCCESS 0x00 -#define NET_XMIT_DROP 0x10 /* skb dropped */ -#define NET_XMIT_CN 0x20 /* congestion notification */ -#define NET_XMIT_POLICED 0x30 /* skb is shot by police */ -#define NET_XMIT_MASK 0xf0 /* qdisc flags in net/sch_generic.h */ - -/* Backlog congestion levels */ -#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ -#define NET_RX_DROP 1 /* packet dropped */ +#define NET_XMIT_DROP 0x01 /* skb dropped */ +#define NET_XMIT_CN 0x02 /* congestion notification */ +#define NET_XMIT_POLICED 0x03 /* skb is shot by police */ +#define NET_XMIT_MASK 0x0f /* qdisc flags in net/sch_generic.h */ /* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It * indicates that the device will soon be dropping packets, or already drops @@ -98,16 +98,34 @@ struct wireless_dev; #define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) /* Driver transmit return codes */ -#define NETDEV_TX_MASK 0xf +#define NETDEV_TX_MASK 0xf0 enum netdev_tx { __NETDEV_TX_MIN = INT_MIN, /* make sure enum is signed */ - NETDEV_TX_OK = 0, /* driver took care of packet */ - NETDEV_TX_BUSY = 1, /* driver tx path was busy*/ - NETDEV_TX_LOCKED = 2, /* driver tx lock was already taken */ + NETDEV_TX_OK = 0x00, /* driver took care of packet */ + NETDEV_TX_BUSY = 0x10, /* driver tx path was busy*/ + NETDEV_TX_LOCKED = 0x20, /* driver tx lock was already taken */ }; typedef enum netdev_tx netdev_tx_t; +/* + * Current order: NETDEV_TX_MASK > NET_XMIT_MASK >= 0 is significant; + * hard_start_xmit() return < NET_XMIT_MASK means skb was consumed. + */ +static inline bool dev_xmit_complete(int rc) +{ + /* + * Positive cases with an skb consumed by a driver: + * - successful transmission (rc == NETDEV_TX_OK) + * - error while transmitting (rc < 0) + * - error while queueing to a different device (rc & NET_XMIT_MASK) + */ + if (likely(rc < NET_XMIT_MASK)) + return true; + + return false; +} + #endif #define MAX_ADDR_LEN 32 /* Largest hardware address length */ diff --git a/net/core/dev.c b/net/core/dev.c index 32045df1da5..4b24d79414e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1924,23 +1924,6 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, return rc; } -static inline bool dev_xmit_complete(int rc) -{ - /* successful transmission */ - if (rc == NETDEV_TX_OK) - return true; - - /* error while transmitting, driver consumed skb */ - if (rc < 0) - return true; - - /* error while queueing to a different device, driver consumed skb */ - if (rc & NET_XMIT_MASK) - return true; - - return false; -} - /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index b13821ad2fb..5173c1e1b19 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -119,39 +119,26 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, spin_unlock(root_lock); HARD_TX_LOCK(dev, txq, smp_processor_id()); - if (!netif_tx_queue_stopped(txq) && - !netif_tx_queue_frozen(txq)) { + if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq)) ret = dev_hard_start_xmit(skb, dev, txq); - /* an error implies that the skb was consumed */ - if (ret < 0) - ret = NETDEV_TX_OK; - /* all NET_XMIT codes map to NETDEV_TX_OK */ - ret &= ~NET_XMIT_MASK; - } HARD_TX_UNLOCK(dev, txq); spin_lock(root_lock); - switch (ret) { - case NETDEV_TX_OK: - /* Driver sent out skb successfully */ + if (dev_xmit_complete(ret)) { + /* Driver sent out skb successfully or skb was consumed */ ret = qdisc_qlen(q); - break; - - case NETDEV_TX_LOCKED: + } else if (ret == NETDEV_TX_LOCKED) { /* Driver try lock failed */ ret = handle_dev_cpu_collision(skb, txq, q); - break; - - default: + } else { /* Driver returned NETDEV_TX_BUSY - requeue skb */ if (unlikely (ret != NETDEV_TX_BUSY && net_ratelimit())) printk(KERN_WARNING "BUG %s code %d qlen %d\n", dev->name, ret, q->q.qlen); ret = dev_requeue_skb(skb, q); - break; } if (ret && (netif_tx_queue_stopped(txq) || -- cgit v1.2.3 From b93ab837a2d3eb394082c9eae4ee0a4f83060027 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 13 Nov 2009 06:33:11 +0000 Subject: vlan: Use __vlan_hwaccel_put_tag() in rx Commit 05423b241311c9380 (vlan: allow null VLAN ID to be used) forgot to update __vlan_hwaccel_rx() & vlan_gro_common() We need to set VLAN_TAG_PRESENT flag in skb->vlan_tci Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlan_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 8d5ca2ac4f8..971d3755ae8 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -14,7 +14,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, if (skb_bond_should_drop(skb)) goto drop; - skb->vlan_tci = vlan_tci; + __vlan_hwaccel_put_tag(skb, vlan_tci); skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); if (!skb->dev) @@ -83,7 +83,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, if (skb_bond_should_drop(skb)) goto drop; - skb->vlan_tci = vlan_tci; + __vlan_hwaccel_put_tag(skb, vlan_tci); skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); if (!skb->dev) -- cgit v1.2.3 From b9f5d52670c27e71f04c466aee77e3a2eeca8080 Mon Sep 17 00:00:00 2001 From: Marin Mitov Date: Fri, 13 Nov 2009 07:58:41 +0000 Subject: remove deprecated and not used: print_mac() The function print_mac in net/ethernet/eth.c is marked __deprecated and not used. Remove it. Signed-off-by: Marin Mitov Signed-off-by: David S. Miller --- include/linux/if_ether.h | 4 ---- net/ethernet/eth.c | 7 ------- 2 files changed, 11 deletions(-) (limited to 'net') diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 580b6004d00..005e1525ab8 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -136,10 +136,6 @@ extern struct ctl_table ether_table[]; extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len); -/* - * Display a 6 byte device address (MAC) in a readable format. - */ -extern char *print_mac(char *buf, const unsigned char *addr) __deprecated; #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" #define MAC_BUF_SIZE 18 #define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE] diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 5a883affecd..dd3db88f8f0 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -393,10 +393,3 @@ ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) return ((ssize_t) l); } EXPORT_SYMBOL(sysfs_format_mac); - -char *print_mac(char *buf, const unsigned char *addr) -{ - _format_mac_addr(buf, MAC_BUF_SIZE, addr, ETH_ALEN); - return buf; -} -EXPORT_SYMBOL(print_mac); -- cgit v1.2.3 From b23709248fc9b6d5877f9c741d639a160ed21ff6 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 16 Nov 2009 19:54:08 +0200 Subject: mac80211: Do not queue Probe Request frames for station MLME Cooked monitor interfaces cannot currently receive Probe Request frames when the interface is in station mode. However, we do not process Probe Request frames internally in the station MLME, so there is no point in queueing the frame here. Remove Probe Request frames from the queued frame list to allow cooked monitor interfaces to receive these frames. Signed-off-by: Jouni Malinen Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dcc14e99227..2af306f67d7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1898,7 +1898,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, fc = le16_to_cpu(mgmt->frame_control); switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: case IEEE80211_STYPE_AUTH: -- cgit v1.2.3 From 649300b9278dc9fc9c7dfaaa3719ead70882e726 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 12:05:34 +0000 Subject: netlink: remove subscriptions check on notifier The netlink URELEASE notifier doesn't notify for sockets that have been used to receive multicast but it should be called for such sockets as well since they might _also_ be used for sending and not solely for receiving multicast. We will need that for nl80211 (generic netlink sockets) in the future. Signed-off-by: Johannes Berg Cc: Patrick McHardy Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index f30d596dbc5..eff5b0ddc5c 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -498,7 +498,7 @@ static int netlink_release(struct socket *sock) skb_queue_purge(&sk->sk_write_queue); - if (nlk->pid && !nlk->subscriptions) { + if (nlk->pid) { struct netlink_notify n = { .net = sock_net(sk), .protocol = sk->sk_protocol, -- cgit v1.2.3 From b2a5decddbe295d09c29d4a8078cdc47a55346df Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Mon, 16 Nov 2009 22:17:24 +0000 Subject: Phonet: missing rcu_dereference() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Paul E. McKenney Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/af_phonet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index ed65da251b6..526d0273991 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -44,7 +44,7 @@ static struct phonet_protocol *phonet_proto_get(int protocol) return NULL; rcu_read_lock(); - pp = proto_tab[protocol]; + pp = rcu_dereference(proto_tab[protocol]); if (pp && !try_module_get(pp->prot->owner)) pp = NULL; rcu_read_unlock(); -- cgit v1.2.3 From feed1f17241d26261e77ddb5f2fc2a91a3c16739 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Tue, 17 Nov 2009 04:14:00 -0800 Subject: act_mirred: cleanup 1. don't let go back using goto. 2. don't call skb_act_clone() until it is necessary. 3. one exit of the critical context. Signed-off-by: Changli Gao Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/act_mirred.c | 59 ++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index b9aaab4e035..b812c20b66c 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -148,47 +148,39 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, { struct tcf_mirred *m = a->priv; struct net_device *dev; - struct sk_buff *skb2 = NULL; - u32 at = G_TC_AT(skb->tc_verd); + struct sk_buff *skb2; + u32 at; + int retval, err = 1; spin_lock(&m->tcf_lock); - - dev = m->tcfm_dev; m->tcf_tm.lastuse = jiffies; + if (m->tcfm_eaction != TCA_EGRESS_MIRROR && + m->tcfm_eaction != TCA_EGRESS_REDIR) { + if (net_ratelimit()) + printk("tcf_mirred unknown action %d\n", + m->tcfm_eaction); + goto out; + } - if (!(dev->flags&IFF_UP) ) { + dev = m->tcfm_dev; + if (!(dev->flags & IFF_UP)) { if (net_ratelimit()) printk("mirred to Houston: device %s is gone!\n", dev->name); -bad_mirred: - if (skb2 != NULL) - kfree_skb(skb2); - m->tcf_qstats.overlimits++; - m->tcf_bstats.bytes += qdisc_pkt_len(skb); - m->tcf_bstats.packets++; - spin_unlock(&m->tcf_lock); - /* should we be asking for packet to be dropped? - * may make sense for redirect case only - */ - return TC_ACT_SHOT; + goto out; } skb2 = skb_act_clone(skb, GFP_ATOMIC); if (skb2 == NULL) - goto bad_mirred; - if (m->tcfm_eaction != TCA_EGRESS_MIRROR && - m->tcfm_eaction != TCA_EGRESS_REDIR) { - if (net_ratelimit()) - printk("tcf_mirred unknown action %d\n", - m->tcfm_eaction); - goto bad_mirred; - } + goto out; m->tcf_bstats.bytes += qdisc_pkt_len(skb2); m->tcf_bstats.packets++; - if (!(at & AT_EGRESS)) + at = G_TC_AT(skb->tc_verd); + if (!(at & AT_EGRESS)) { if (m->tcfm_ok_push) skb_push(skb2, skb2->dev->hard_header_len); + } /* mirror is always swallowed */ if (m->tcfm_eaction != TCA_EGRESS_MIRROR) @@ -197,8 +189,23 @@ bad_mirred: skb2->dev = dev; skb2->iif = skb->dev->ifindex; dev_queue_xmit(skb2); + err = 0; + +out: + if (err) { + m->tcf_qstats.overlimits++; + m->tcf_bstats.bytes += qdisc_pkt_len(skb); + m->tcf_bstats.packets++; + /* should we be asking for packet to be dropped? + * may make sense for redirect case only + */ + retval = TC_ACT_SHOT; + } else { + retval = m->tcf_action; + } spin_unlock(&m->tcf_lock); - return m->tcf_action; + + return retval; } static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) -- cgit v1.2.3 From b76965e02bfdd4164c00bf946ff6ca1818ed9fcd Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Tue, 17 Nov 2009 04:15:16 -0800 Subject: act_mirred: optimization. move checking if eaction is valid in tcf_mirred_init() Signed-off-by: Changli Gao Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/act_mirred.c | 60 ++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index b812c20b66c..79747936988 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -65,48 +65,53 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, struct tc_mirred *parm; struct tcf_mirred *m; struct tcf_common *pc; - struct net_device *dev = NULL; - int ret = 0, err; - int ok_push = 0; + struct net_device *dev; + int ret, ok_push = 0; if (nla == NULL) return -EINVAL; - - err = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy); - if (err < 0) - return err; - + ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy); + if (ret < 0) + return ret; if (tb[TCA_MIRRED_PARMS] == NULL) return -EINVAL; parm = nla_data(tb[TCA_MIRRED_PARMS]); - + switch (parm->eaction) { + case TCA_EGRESS_MIRROR: + case TCA_EGRESS_REDIR: + break; + default: + return -EINVAL; + } if (parm->ifindex) { dev = __dev_get_by_index(&init_net, parm->ifindex); if (dev == NULL) return -ENODEV; switch (dev->type) { - case ARPHRD_TUNNEL: - case ARPHRD_TUNNEL6: - case ARPHRD_SIT: - case ARPHRD_IPGRE: - case ARPHRD_VOID: - case ARPHRD_NONE: - ok_push = 0; - break; - default: - ok_push = 1; - break; + case ARPHRD_TUNNEL: + case ARPHRD_TUNNEL6: + case ARPHRD_SIT: + case ARPHRD_IPGRE: + case ARPHRD_VOID: + case ARPHRD_NONE: + ok_push = 0; + break; + default: + ok_push = 1; + break; } + } else { + dev = NULL; } pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info); if (!pc) { - if (!parm->ifindex) + if (dev == NULL) return -EINVAL; pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, &mirred_idx_gen, &mirred_hash_info); if (IS_ERR(pc)) - return PTR_ERR(pc); + return PTR_ERR(pc); ret = ACT_P_CREATED; } else { if (!ovr) { @@ -119,12 +124,12 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, spin_lock_bh(&m->tcf_lock); m->tcf_action = parm->action; m->tcfm_eaction = parm->eaction; - if (parm->ifindex) { + if (dev != NULL) { m->tcfm_ifindex = parm->ifindex; if (ret != ACT_P_CREATED) dev_put(m->tcfm_dev); - m->tcfm_dev = dev; dev_hold(dev); + m->tcfm_dev = dev; m->tcfm_ok_push = ok_push; } spin_unlock_bh(&m->tcf_lock); @@ -154,13 +159,6 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, spin_lock(&m->tcf_lock); m->tcf_tm.lastuse = jiffies; - if (m->tcfm_eaction != TCA_EGRESS_MIRROR && - m->tcfm_eaction != TCA_EGRESS_REDIR) { - if (net_ratelimit()) - printk("tcf_mirred unknown action %d\n", - m->tcfm_eaction); - goto out; - } dev = m->tcfm_dev; if (!(dev->flags & IFF_UP)) { -- cgit v1.2.3 From d83345adf96bc13a5e360f4649a2e68ef968dec0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Nov 2009 03:36:51 +0000 Subject: net: add dev_txq_stats_fold() helper Some drivers ndo_get_stats() method need to perform txqueue stats folding. Move folding from dev_get_stats() to a new dev_txq_stats_fold() function Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + net/core/dev.c | 48 ++++++++++++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7043f85e643..c8fa4627de0 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1941,6 +1941,7 @@ extern void netdev_features_change(struct net_device *dev); extern void dev_load(struct net *net, const char *name); extern void dev_mcast_init(void); extern const struct net_device_stats *dev_get_stats(struct net_device *dev); +extern void dev_txq_stats_fold(const struct net_device *dev, struct net_device_stats *stats); extern int netdev_max_backlog; extern int weight_p; diff --git a/net/core/dev.c b/net/core/dev.c index d867522290b..c3e0578d29d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5168,6 +5168,32 @@ void netdev_run_todo(void) } } +/** + * dev_txq_stats_fold - fold tx_queues stats + * @dev: device to get statistics from + * @stats: struct net_device_stats to hold results + */ +void dev_txq_stats_fold(const struct net_device *dev, + struct net_device_stats *stats) +{ + unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0; + unsigned int i; + struct netdev_queue *txq; + + for (i = 0; i < dev->num_tx_queues; i++) { + txq = netdev_get_tx_queue(dev, i); + tx_bytes += txq->tx_bytes; + tx_packets += txq->tx_packets; + tx_dropped += txq->tx_dropped; + } + if (tx_bytes || tx_packets || tx_dropped) { + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + stats->tx_dropped = tx_dropped; + } +} +EXPORT_SYMBOL(dev_txq_stats_fold); + /** * dev_get_stats - get network device statistics * @dev: device to get statistics from @@ -5182,25 +5208,9 @@ const struct net_device_stats *dev_get_stats(struct net_device *dev) if (ops->ndo_get_stats) return ops->ndo_get_stats(dev); - else { - unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0; - struct net_device_stats *stats = &dev->stats; - unsigned int i; - struct netdev_queue *txq; - - for (i = 0; i < dev->num_tx_queues; i++) { - txq = netdev_get_tx_queue(dev, i); - tx_bytes += txq->tx_bytes; - tx_packets += txq->tx_packets; - tx_dropped += txq->tx_dropped; - } - if (tx_bytes || tx_packets || tx_dropped) { - stats->tx_bytes = tx_bytes; - stats->tx_packets = tx_packets; - stats->tx_dropped = tx_dropped; - } - return stats; - } + + dev_txq_stats_fold(dev, &dev->stats); + return &dev->stats; } EXPORT_SYMBOL(dev_get_stats); -- cgit v1.2.3 From 9793241fe92f7d9303fb221e43fc598eb065f267 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Nov 2009 04:53:09 +0000 Subject: vlan: Precise RX stats accounting With multi queue devices, its possible that several cpus call vlan RX routines simultaneously for the same vlan device. We update RX stats counter without any locking, so we can get slightly wrong counters. One possible fix is to use percpu counters, to get precise accounting and also get guarantee of no cache line ping pongs between cpus. Note: this adds 16 bytes (32 bytes on 64bit arches) of percpu data per vlan device. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlan.h | 17 +++++++++++++++++ net/8021q/vlan_core.c | 12 +++++++----- net/8021q/vlan_dev.c | 47 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 68f9290e683..5685296017e 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -16,6 +16,21 @@ struct vlan_priority_tci_mapping { struct vlan_priority_tci_mapping *next; }; + +/** + * struct vlan_rx_stats - VLAN percpu rx stats + * @rx_packets: number of received packets + * @rx_bytes: number of received bytes + * @multicast: number of received multicast packets + * @rx_errors: number of errors + */ +struct vlan_rx_stats { + unsigned long rx_packets; + unsigned long rx_bytes; + unsigned long multicast; + unsigned long rx_errors; +}; + /** * struct vlan_dev_info - VLAN private device data * @nr_ingress_mappings: number of ingress priority mappings @@ -29,6 +44,7 @@ struct vlan_priority_tci_mapping { * @dent: proc dir entry * @cnt_inc_headroom_on_tx: statistic - number of skb expansions on TX * @cnt_encap_on_xmit: statistic - number of skb encapsulations on TX + * @vlan_rx_stats: ptr to percpu rx stats */ struct vlan_dev_info { unsigned int nr_ingress_mappings; @@ -45,6 +61,7 @@ struct vlan_dev_info { struct proc_dir_entry *dent; unsigned long cnt_inc_headroom_on_tx; unsigned long cnt_encap_on_xmit; + struct vlan_rx_stats *vlan_rx_stats; }; static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 971d3755ae8..e75a2f3b10a 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -31,7 +31,7 @@ EXPORT_SYMBOL(__vlan_hwaccel_rx); int vlan_hwaccel_do_receive(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct net_device_stats *stats; + struct vlan_rx_stats *rx_stats; skb->dev = vlan_dev_info(dev)->real_dev; netif_nit_deliver(skb); @@ -40,15 +40,17 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb) skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci); skb->vlan_tci = 0; - stats = &dev->stats; - stats->rx_packets++; - stats->rx_bytes += skb->len; + rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, + smp_processor_id()); + + rx_stats->rx_packets++; + rx_stats->rx_bytes += skb->len; switch (skb->pkt_type) { case PACKET_BROADCAST: break; case PACKET_MULTICAST: - stats->multicast++; + rx_stats->multicast++; break; case PACKET_OTHERHOST: /* Our lower layer thinks this is not local, let's make sure. diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 91596594213..de0dc6bacbe 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -140,7 +140,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { struct vlan_hdr *vhdr; - struct net_device_stats *stats; + struct vlan_rx_stats *rx_stats; u16 vlan_id; u16 vlan_tci; @@ -163,9 +163,10 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, goto err_unlock; } - stats = &skb->dev->stats; - stats->rx_packets++; - stats->rx_bytes += skb->len; + rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, + smp_processor_id()); + rx_stats->rx_packets++; + rx_stats->rx_bytes += skb->len; skb_pull_rcsum(skb, VLAN_HLEN); @@ -180,7 +181,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, break; case PACKET_MULTICAST: - stats->multicast++; + rx_stats->multicast++; break; case PACKET_OTHERHOST: @@ -200,7 +201,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, skb = vlan_check_reorder_header(skb); if (!skb) { - stats->rx_errors++; + rx_stats->rx_errors++; goto err_unlock; } @@ -731,6 +732,11 @@ static int vlan_dev_init(struct net_device *dev) subclass = 1; vlan_dev_set_lockdep_class(dev, subclass); + + vlan_dev_info(dev)->vlan_rx_stats = alloc_percpu(struct vlan_rx_stats); + if (!vlan_dev_info(dev)->vlan_rx_stats) + return -ENOMEM; + return 0; } @@ -740,6 +746,8 @@ static void vlan_dev_uninit(struct net_device *dev) struct vlan_dev_info *vlan = vlan_dev_info(dev); int i; + free_percpu(vlan->vlan_rx_stats); + vlan->vlan_rx_stats = NULL; for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { while ((pm = vlan->egress_priority_map[i]) != NULL) { vlan->egress_priority_map[i] = pm->next; @@ -775,6 +783,31 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev) return dev_ethtool_get_flags(vlan->real_dev); } +static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev) +{ + struct net_device_stats *stats = &dev->stats; + + dev_txq_stats_fold(dev, stats); + + if (vlan_dev_info(dev)->vlan_rx_stats) { + struct vlan_rx_stats *p, rx = {0}; + int i; + + for_each_possible_cpu(i) { + p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i); + rx.rx_packets += p->rx_packets; + rx.rx_bytes += p->rx_bytes; + rx.rx_errors += p->rx_errors; + rx.multicast += p->multicast; + } + stats->rx_packets = rx.rx_packets; + stats->rx_bytes = rx.rx_bytes; + stats->rx_errors = rx.rx_errors; + stats->multicast = rx.multicast; + } + return stats; +} + static const struct ethtool_ops vlan_ethtool_ops = { .get_settings = vlan_ethtool_get_settings, .get_drvinfo = vlan_ethtool_get_drvinfo, @@ -797,6 +830,7 @@ static const struct net_device_ops vlan_netdev_ops = { .ndo_change_rx_flags = vlan_dev_change_rx_flags, .ndo_do_ioctl = vlan_dev_ioctl, .ndo_neigh_setup = vlan_dev_neigh_setup, + .ndo_get_stats = vlan_dev_get_stats, #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, @@ -820,6 +854,7 @@ static const struct net_device_ops vlan_netdev_accel_ops = { .ndo_change_rx_flags = vlan_dev_change_rx_flags, .ndo_do_ioctl = vlan_dev_ioctl, .ndo_neigh_setup = vlan_dev_neigh_setup, + .ndo_get_stats = vlan_dev_get_stats, #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, -- cgit v1.2.3 From 395264d509aec45149745843d9a737140a1ece16 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Mon, 16 Nov 2009 13:49:35 +0000 Subject: net: introduce NETDEV_UNREGISTER_PERNET This new event is called once for each unique net namespace in batched unregister operations (with the argument set to a random device from that namespace) and once per device in non-batched unregister operations. It allows us to factorize some device unregister work such as clearing the routing cache. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/linux/notifier.h | 1 + net/core/dev.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 29714b8441b..b0c3671d463 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -202,6 +202,7 @@ static inline int notifier_to_errno(int ret) #define NETDEV_BONDING_OLDTYPE 0x000E #define NETDEV_BONDING_NEWTYPE 0x000F #define NETDEV_POST_INIT 0x0010 +#define NETDEV_UNREGISTER_PERNET 0x0011 #define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_RESTART SYS_DOWN diff --git a/net/core/dev.c b/net/core/dev.c index c3e0578d29d..e25fe5d9343 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1344,6 +1344,7 @@ rollback: nb->notifier_call(nb, NETDEV_DOWN, dev); } nb->notifier_call(nb, NETDEV_UNREGISTER, dev); + nb->notifier_call(nb, NETDEV_UNREGISTER_PERNET, dev); } } @@ -4721,7 +4722,8 @@ static void net_set_todo(struct net_device *dev) static void rollback_registered_many(struct list_head *head) { - struct net_device *dev; + struct net_device *dev, *aux, *fdev; + LIST_HEAD(pernet_list); BUG_ON(dev_boot_phase); ASSERT_RTNL(); @@ -4779,8 +4781,24 @@ static void rollback_registered_many(struct list_head *head) synchronize_net(); - list_for_each_entry(dev, head, unreg_list) + list_for_each_entry_safe(dev, aux, head, unreg_list) { + int new_net = 1; + list_for_each_entry(fdev, &pernet_list, unreg_list) { + if (dev_net(dev) == dev_net(fdev)) { + new_net = 0; + dev_put(dev); + break; + } + } + if (new_net) + list_move(&dev->unreg_list, &pernet_list); + } + + list_for_each_entry_safe(dev, aux, &pernet_list, unreg_list) { + call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev); + list_move(&dev->unreg_list, head); dev_put(dev); + } } static void rollback_registered(struct net_device *dev) @@ -5074,6 +5092,8 @@ static void netdev_wait_allrefs(struct net_device *dev) /* Rebroadcast unregister notification */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); + /* don't resend NETDEV_UNREGISTER_PERNET, _PERNET users + * should have already handle it the first time */ if (test_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { @@ -5385,6 +5405,10 @@ EXPORT_SYMBOL(unregister_netdevice_queue); * unregister_netdevice_many - unregister many devices * @head: list of devices * + * WARNING: Calling this modifies the given list + * (in rollback_registered_many). It may change the order of the elements + * in the list. However, you can assume it does not add or delete elements + * to/from the list. */ void unregister_netdevice_many(struct list_head *head) { @@ -5504,6 +5528,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char this device. They should clean all the things. */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); + call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev); /* * Flush the unicast and multicast chains -- cgit v1.2.3 From e2ce146848c81af2f6d42e67990191c284bf0c33 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Mon, 16 Nov 2009 13:49:49 +0000 Subject: ipv4: factorize cache clearing for batched unregister operations Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 816e2180bd6..6c1e56aef1f 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -895,11 +895,11 @@ static void nl_fib_lookup_exit(struct net *net) net->ipv4.fibnl = NULL; } -static void fib_disable_ip(struct net_device *dev, int force) +static void fib_disable_ip(struct net_device *dev, int force, int delay) { if (fib_sync_down_dev(dev, force)) fib_flush(dev_net(dev)); - rt_cache_flush(dev_net(dev), 0); + rt_cache_flush(dev_net(dev), delay); arp_ifdown(dev); } @@ -922,7 +922,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, /* Last address was deleted from this interface. Disable IP. */ - fib_disable_ip(dev, 1); + fib_disable_ip(dev, 1, 0); } else { rt_cache_flush(dev_net(dev), -1); } @@ -937,7 +937,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo struct in_device *in_dev = __in_dev_get_rtnl(dev); if (event == NETDEV_UNREGISTER) { - fib_disable_ip(dev, 2); + fib_disable_ip(dev, 2, -1); return NOTIFY_DONE; } @@ -955,10 +955,11 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo rt_cache_flush(dev_net(dev), -1); break; case NETDEV_DOWN: - fib_disable_ip(dev, 0); + fib_disable_ip(dev, 0, 0); break; case NETDEV_CHANGEMTU: case NETDEV_CHANGE: + case NETDEV_UNREGISTER_PERNET: rt_cache_flush(dev_net(dev), 0); break; } -- cgit v1.2.3 From e014debecd3ee3832e6476b3a9c948edfcfd1250 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Nov 2009 05:59:21 +0000 Subject: linkwatch: linkwatch_forget_dev() to speedup device dismantle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Herbert Xu a écrit : > On Tue, Nov 17, 2009 at 04:26:04AM -0800, David Miller wrote: >> Really, the link watch stuff is just due for a redesign. I don't >> think a simple hack is going to cut it this time, sorry Eric :-) > > I have no objections against any redesigns, but since the only > caller of linkwatch_forget_dev runs in process context with the > RTNL, it could also legally emit those events. Thanks guys, here an updated version then, before linkwatch surgery ? In this version, I force the event to be sent synchronously. [PATCH net-next-2.6] linkwatch: linkwatch_forget_dev() to speedup device dismantle time ip link del eth3.103 ; time ip link del eth3.104 ; time ip link del eth3.105 real 0m0.266s user 0m0.000s sys 0m0.001s real 0m0.770s user 0m0.000s sys 0m0.000s real 0m1.022s user 0m0.000s sys 0m0.000s One problem of current schem in vlan dismantle phase is the holding of device done by following chain : vlan_dev_stop() -> netif_carrier_off(dev) -> linkwatch_fire_event(dev) -> dev_hold() ... And __linkwatch_run_queue() runs up to one second later... A generic fix to this problem is to add a linkwatch_forget_dev() method to unlink the device from the list of watched devices. dev->link_watch_next becomes dev->link_watch_list (and use a bit more memory), to be able to unlink device in O(1). After patch : time ip link del eth3.103 ; time ip link del eth3.104 ; time ip link del eth3.105 real 0m0.024s user 0m0.000s sys 0m0.000s real 0m0.032s user 0m0.000s sys 0m0.001s real 0m0.033s user 0m0.000s sys 0m0.000s Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +- net/core/dev.c | 3 ++ net/core/link_watch.c | 94 ++++++++++++++++++++++++++++------------------- 3 files changed, 62 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c8fa4627de0..97873e31661 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -896,7 +896,7 @@ struct net_device { /* device index hash chain */ struct hlist_node index_hlist; - struct net_device *link_watch_next; + struct list_head link_watch_list; /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, @@ -1600,6 +1600,7 @@ static inline void dev_hold(struct net_device *dev) */ extern void linkwatch_fire_event(struct net_device *dev); +extern void linkwatch_forget_dev(struct net_device *dev); /** * netif_carrier_ok - test if carrier present diff --git a/net/core/dev.c b/net/core/dev.c index e25fe5d9343..c128af708eb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5085,6 +5085,8 @@ static void netdev_wait_allrefs(struct net_device *dev) { unsigned long rebroadcast_time, warning_time; + linkwatch_forget_dev(dev); + rebroadcast_time = warning_time = jiffies; while (atomic_read(&dev->refcnt) != 0) { if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { @@ -5311,6 +5313,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, INIT_LIST_HEAD(&dev->napi_list); INIT_LIST_HEAD(&dev->unreg_list); + INIT_LIST_HEAD(&dev->link_watch_list); dev->priv_flags = IFF_XMIT_DST_RELEASE; setup(dev); strcpy(dev->name, name); diff --git a/net/core/link_watch.c b/net/core/link_watch.c index bf8f7af699d..5910b555a54 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -35,7 +35,7 @@ static unsigned long linkwatch_nextevent; static void linkwatch_event(struct work_struct *dummy); static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); -static struct net_device *lweventlist; +static LIST_HEAD(lweventlist); static DEFINE_SPINLOCK(lweventlist_lock); static unsigned char default_operstate(const struct net_device *dev) @@ -89,8 +89,10 @@ static void linkwatch_add_event(struct net_device *dev) unsigned long flags; spin_lock_irqsave(&lweventlist_lock, flags); - dev->link_watch_next = lweventlist; - lweventlist = dev; + if (list_empty(&dev->link_watch_list)) { + list_add_tail(&dev->link_watch_list, &lweventlist); + dev_hold(dev); + } spin_unlock_irqrestore(&lweventlist_lock, flags); } @@ -133,9 +135,35 @@ static void linkwatch_schedule_work(int urgent) } +static void linkwatch_do_dev(struct net_device *dev) +{ + /* + * Make sure the above read is complete since it can be + * rewritten as soon as we clear the bit below. + */ + smp_mb__before_clear_bit(); + + /* We are about to handle this device, + * so new events can be accepted + */ + clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); + + rfc2863_policy(dev); + if (dev->flags & IFF_UP) { + if (netif_carrier_ok(dev)) + dev_activate(dev); + else + dev_deactivate(dev); + + netdev_state_change(dev); + } + dev_put(dev); +} + static void __linkwatch_run_queue(int urgent_only) { - struct net_device *next; + struct net_device *dev; + LIST_HEAD(wrk); /* * Limit the number of linkwatch events to one @@ -153,46 +181,40 @@ static void __linkwatch_run_queue(int urgent_only) clear_bit(LW_URGENT, &linkwatch_flags); spin_lock_irq(&lweventlist_lock); - next = lweventlist; - lweventlist = NULL; - spin_unlock_irq(&lweventlist_lock); + list_splice_init(&lweventlist, &wrk); - while (next) { - struct net_device *dev = next; + while (!list_empty(&wrk)) { - next = dev->link_watch_next; + dev = list_first_entry(&wrk, struct net_device, link_watch_list); + list_del_init(&dev->link_watch_list); if (urgent_only && !linkwatch_urgent_event(dev)) { - linkwatch_add_event(dev); + list_add_tail(&dev->link_watch_list, &lweventlist); continue; } - - /* - * Make sure the above read is complete since it can be - * rewritten as soon as we clear the bit below. - */ - smp_mb__before_clear_bit(); - - /* We are about to handle this device, - * so new events can be accepted - */ - clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); - - rfc2863_policy(dev); - if (dev->flags & IFF_UP) { - if (netif_carrier_ok(dev)) - dev_activate(dev); - else - dev_deactivate(dev); - - netdev_state_change(dev); - } - - dev_put(dev); + spin_unlock_irq(&lweventlist_lock); + linkwatch_do_dev(dev); + spin_lock_irq(&lweventlist_lock); } - if (lweventlist) + if (!list_empty(&lweventlist)) linkwatch_schedule_work(0); + spin_unlock_irq(&lweventlist_lock); +} + +void linkwatch_forget_dev(struct net_device *dev) +{ + unsigned long flags; + int clean = 0; + + spin_lock_irqsave(&lweventlist_lock, flags); + if (!list_empty(&dev->link_watch_list)) { + list_del_init(&dev->link_watch_list); + clean = 1; + } + spin_unlock_irqrestore(&lweventlist_lock, flags); + if (clean) + linkwatch_do_dev(dev); } @@ -216,8 +238,6 @@ void linkwatch_fire_event(struct net_device *dev) bool urgent = linkwatch_urgent_event(dev); if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { - dev_hold(dev); - linkwatch_add_event(dev); } else if (!urgent) return; -- cgit v1.2.3 From f99189b186f3922ede4fa33c02f6edc735b8c981 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Nov 2009 10:42:49 +0000 Subject: netns: net_identifiers should be read_mostly Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- drivers/net/ppp_generic.c | 2 +- drivers/net/pppoe.c | 2 +- drivers/net/pppol2tp.c | 2 +- net/8021q/vlan.c | 2 +- net/ipv4/ip_gre.c | 2 +- net/ipv4/ipip.c | 2 +- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/sit.c | 2 +- net/key/af_key.c | 2 +- net/netfilter/nf_conntrack_proto_dccp.c | 2 +- net/netfilter/nf_conntrack_proto_gre.c | 2 +- net/phonet/pn_dev.c | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ecea6c29413..726bd755338 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -158,7 +158,7 @@ MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the static const char * const version = DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; -int bond_net_id; +int bond_net_id __read_mostly; static __be32 arp_target[BOND_MAX_ARP_TARGETS]; static int arp_ip_count; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 965adb6174c..0a56a778af0 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -184,7 +184,7 @@ static atomic_t ppp_unit_count = ATOMIC_INIT(0); static atomic_t channel_count = ATOMIC_INIT(0); /* per-net private data for this module */ -static int ppp_net_id; +static int ppp_net_id __read_mostly; struct ppp_net { /* units to ppp mapping */ struct idr units_idr; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 60c8d233209..a1dcba255b0 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -97,7 +97,7 @@ static const struct proto_ops pppoe_ops; static struct ppp_channel_ops pppoe_chan_ops; /* per-net private data for this module */ -static int pppoe_net_id; +static int pppoe_net_id __read_mostly; struct pppoe_net { /* * we could use _single_ hash table for all diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 849cc9c62c2..442c382c2c8 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -232,7 +232,7 @@ static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit , NULL }; static const struct proto_ops pppol2tp_ops; /* per-net private data for this module */ -static int pppol2tp_net_id; +static int pppol2tp_net_id __read_mostly; struct pppol2tp_net { struct list_head pppol2tp_tunnel_list; rwlock_t pppol2tp_tunnel_list_lock; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 39f8d012010..d9cb020029b 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -41,7 +41,7 @@ /* Global VLAN variables */ -int vlan_net_id; +int vlan_net_id __read_mostly; /* Our listing of VLAN group(s) */ static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index a7de9e3a8f1..c5f6af5d0f3 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -125,7 +125,7 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev); #define HASH_SIZE 16 -static int ipgre_net_id; +static int ipgre_net_id __read_mostly; struct ipgre_net { struct ip_tunnel *tunnels[4][HASH_SIZE]; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index c5b1f71c3cd..7242ffcc44e 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -119,7 +119,7 @@ #define HASH_SIZE 16 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) -static int ipip_net_id; +static int ipip_net_id __read_mostly; struct ipip_net { struct ip_tunnel *tunnels_r_l[HASH_SIZE]; struct ip_tunnel *tunnels_r[HASH_SIZE]; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 1d614113a4b..e5c0f6bb831 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -78,7 +78,7 @@ static void ip6_fb_tnl_dev_init(struct net_device *dev); static void ip6_tnl_dev_init(struct net_device *dev); static void ip6_tnl_dev_setup(struct net_device *dev); -static int ip6_tnl_net_id; +static int ip6_tnl_net_id __read_mostly; struct ip6_tnl_net { /* the IPv6 tunnel fallback device */ struct net_device *fb_tnl_dev; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index b6e145a673a..d9deaa7753e 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -66,7 +66,7 @@ static void ipip6_fb_tunnel_init(struct net_device *dev); static void ipip6_tunnel_init(struct net_device *dev); static void ipip6_tunnel_setup(struct net_device *dev); -static int sit_net_id; +static int sit_net_id __read_mostly; struct sit_net { struct ip_tunnel *tunnels_r_l[HASH_SIZE]; struct ip_tunnel *tunnels_r[HASH_SIZE]; diff --git a/net/key/af_key.c b/net/key/af_key.c index 86b2c22d091..478c8b32a5f 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -35,7 +35,7 @@ #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x)) #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x)) -static int pfkey_net_id; +static int pfkey_net_id __read_mostly; struct netns_pfkey { /* List of all pfkey sockets. */ struct hlist_head table; diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 1b816a2ea81..80abdf297b3 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -384,7 +384,7 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = }; /* this module per-net specifics */ -static int dccp_net_id; +static int dccp_net_id __read_mostly; struct dccp_net { int dccp_loose; unsigned int dccp_timeout[CT_DCCP_MAX + 1]; diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index a54a0af0edb..91d0e719d67 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -43,7 +43,7 @@ #define GRE_TIMEOUT (30 * HZ) #define GRE_STREAM_TIMEOUT (180 * HZ) -static int proto_gre_net_id; +static int proto_gre_net_id __read_mostly; struct netns_proto_gre { rwlock_t keymap_lock; struct list_head keymap_list; diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 3287f8f0b5c..d5ad7947d77 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -43,7 +43,7 @@ struct phonet_net { struct phonet_routes routes; }; -int phonet_net_id; +int phonet_net_id __read_mostly; struct phonet_device_list *phonet_device_list(struct net *net) { -- cgit v1.2.3 From d90310243fd750240755e217c5faa13e24f41536 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 18 Nov 2009 02:36:59 +0000 Subject: net: device name allocation cleanups Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/core/dev.c | 69 ++++++++++++++++++++-------------------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index c128af708eb..9977288583b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -893,7 +893,8 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf) free_page((unsigned long) inuse); } - snprintf(buf, IFNAMSIZ, name, i); + if (buf != name) + snprintf(buf, IFNAMSIZ, name, i); if (!__dev_get_by_name(net, buf)) return i; @@ -933,6 +934,21 @@ int dev_alloc_name(struct net_device *dev, const char *name) } EXPORT_SYMBOL(dev_alloc_name); +static int dev_get_valid_name(struct net *net, const char *name, char *buf, + bool fmt) +{ + if (!dev_valid_name(name)) + return -EINVAL; + + if (fmt && strchr(name, '%')) + return __dev_alloc_name(net, name, buf); + else if (__dev_get_by_name(net, name)) + return -EEXIST; + else if (buf != name) + strlcpy(buf, name, IFNAMSIZ); + + return 0; +} /** * dev_change_name - change name of a device @@ -956,22 +972,14 @@ int dev_change_name(struct net_device *dev, const char *newname) if (dev->flags & IFF_UP) return -EBUSY; - if (!dev_valid_name(newname)) - return -EINVAL; - if (strncmp(newname, dev->name, IFNAMSIZ) == 0) return 0; memcpy(oldname, dev->name, IFNAMSIZ); - if (strchr(newname, '%')) { - err = dev_alloc_name(dev, newname); - if (err < 0) - return err; - } else if (__dev_get_by_name(net, newname)) - return -EEXIST; - else - strlcpy(dev->name, newname, IFNAMSIZ); + err = dev_get_valid_name(net, newname, dev->name, 1); + if (err < 0) + return err; rollback: /* For now only devices in the initial network namespace @@ -4883,8 +4891,6 @@ EXPORT_SYMBOL(netdev_fix_features); int register_netdevice(struct net_device *dev) { - struct hlist_head *head; - struct hlist_node *p; int ret; struct net *net = dev_net(dev); @@ -4913,26 +4919,14 @@ int register_netdevice(struct net_device *dev) } } - if (!dev_valid_name(dev->name)) { - ret = -EINVAL; + ret = dev_get_valid_name(net, dev->name, dev->name, 0); + if (ret) goto err_uninit; - } dev->ifindex = dev_new_index(net); if (dev->iflink == -1) dev->iflink = dev->ifindex; - /* Check for existence of name */ - head = dev_name_hash(net, dev->name); - hlist_for_each(p, head) { - struct net_device *d - = hlist_entry(p, struct net_device, name_hlist); - if (!strncmp(d->name, dev->name, IFNAMSIZ)) { - ret = -EEXIST; - goto err_uninit; - } - } - /* Fix illegal checksum combinations */ if ((dev->features & NETIF_F_HW_CSUM) && (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { @@ -5460,8 +5454,6 @@ EXPORT_SYMBOL(unregister_netdev); int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) { - char buf[IFNAMSIZ]; - const char *destname; int err; ASSERT_RTNL(); @@ -5494,20 +5486,11 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char * we can use it in the destination network namespace. */ err = -EEXIST; - destname = dev->name; - if (__dev_get_by_name(net, destname)) { + if (__dev_get_by_name(net, dev->name)) { /* We get here if we can't use the current device name */ if (!pat) goto out; - if (!dev_valid_name(pat)) - goto out; - if (strchr(pat, '%')) { - if (__dev_alloc_name(net, pat, buf) < 0) - goto out; - destname = buf; - } else - destname = pat; - if (__dev_get_by_name(net, destname)) + if (dev_get_valid_name(net, pat, dev->name, 1)) goto out; } @@ -5544,10 +5527,6 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Actually switch the network namespace */ dev_net_set(dev, net); - /* Assign the new device name */ - if (destname != dev->name) - strcpy(dev->name, destname); - /* If there is an ifindex conflict assign a new one */ if (__dev_get_by_index(net, dev->ifindex)) { int iflink = (dev->iflink == dev->ifindex); -- cgit v1.2.3 From eeb74a9d45f781ec6f47b9e0a75a6a427b53f165 Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 18 Nov 2009 10:08:26 -0800 Subject: Phonet: convert devices list to RCU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/net/phonet/pn_dev.h | 2 +- net/phonet/pn_dev.c | 63 +++++++++++++++++++++++++++++---------------- net/phonet/pn_netlink.c | 6 ++--- 3 files changed, 45 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index afa7defceb1..d7b989ca3d6 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h @@ -25,7 +25,7 @@ struct phonet_device_list { struct list_head list; - spinlock_t lock; + struct mutex lock; }; struct phonet_device_list *phonet_device_list(struct net *net); diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index d5ad7947d77..d87388c94b0 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -61,7 +61,8 @@ static struct phonet_device *__phonet_device_alloc(struct net_device *dev) pnd->netdev = dev; bitmap_zero(pnd->addrs, 64); - list_add(&pnd->list, &pndevs->list); + BUG_ON(!mutex_is_locked(&pndevs->lock)); + list_add_rcu(&pnd->list, &pndevs->list); return pnd; } @@ -70,6 +71,7 @@ static struct phonet_device *__phonet_get(struct net_device *dev) struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); struct phonet_device *pnd; + BUG_ON(!mutex_is_locked(&pndevs->lock)); list_for_each_entry(pnd, &pndevs->list, list) { if (pnd->netdev == dev) return pnd; @@ -77,6 +79,18 @@ static struct phonet_device *__phonet_get(struct net_device *dev) return NULL; } +static struct phonet_device *__phonet_get_rcu(struct net_device *dev) +{ + struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); + struct phonet_device *pnd; + + list_for_each_entry_rcu(pnd, &pndevs->list, list) { + if (pnd->netdev == dev) + return pnd; + } + return NULL; +} + static void phonet_device_destroy(struct net_device *dev) { struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); @@ -84,11 +98,11 @@ static void phonet_device_destroy(struct net_device *dev) ASSERT_RTNL(); - spin_lock_bh(&pndevs->lock); + mutex_lock(&pndevs->lock); pnd = __phonet_get(dev); if (pnd) - list_del(&pnd->list); - spin_unlock_bh(&pndevs->lock); + list_del_rcu(&pnd->list); + mutex_unlock(&pndevs->lock); if (pnd) { u8 addr; @@ -106,8 +120,8 @@ struct net_device *phonet_device_get(struct net *net) struct phonet_device *pnd; struct net_device *dev = NULL; - spin_lock_bh(&pndevs->lock); - list_for_each_entry(pnd, &pndevs->list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pnd, &pndevs->list, list) { dev = pnd->netdev; BUG_ON(!dev); @@ -118,7 +132,7 @@ struct net_device *phonet_device_get(struct net *net) } if (dev) dev_hold(dev); - spin_unlock_bh(&pndevs->lock); + rcu_read_unlock(); return dev; } @@ -128,7 +142,7 @@ int phonet_address_add(struct net_device *dev, u8 addr) struct phonet_device *pnd; int err = 0; - spin_lock_bh(&pndevs->lock); + mutex_lock(&pndevs->lock); /* Find or create Phonet-specific device data */ pnd = __phonet_get(dev); if (pnd == NULL) @@ -137,7 +151,7 @@ int phonet_address_add(struct net_device *dev, u8 addr) err = -ENOMEM; else if (test_and_set_bit(addr >> 2, pnd->addrs)) err = -EEXIST; - spin_unlock_bh(&pndevs->lock); + mutex_unlock(&pndevs->lock); return err; } @@ -147,27 +161,32 @@ int phonet_address_del(struct net_device *dev, u8 addr) struct phonet_device *pnd; int err = 0; - spin_lock_bh(&pndevs->lock); + mutex_lock(&pndevs->lock); pnd = __phonet_get(dev); - if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) + if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) { err = -EADDRNOTAVAIL; - else if (bitmap_empty(pnd->addrs, 64)) { - list_del(&pnd->list); + pnd = NULL; + } else if (bitmap_empty(pnd->addrs, 64)) + list_del_rcu(&pnd->list); + else + pnd = NULL; + mutex_unlock(&pndevs->lock); + + if (pnd) { + synchronize_rcu(); kfree(pnd); } - spin_unlock_bh(&pndevs->lock); return err; } /* Gets a source address toward a destination, through a interface. */ u8 phonet_address_get(struct net_device *dev, u8 daddr) { - struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); struct phonet_device *pnd; u8 saddr; - spin_lock_bh(&pndevs->lock); - pnd = __phonet_get(dev); + rcu_read_lock(); + pnd = __phonet_get_rcu(dev); if (pnd) { BUG_ON(bitmap_empty(pnd->addrs, 64)); @@ -178,7 +197,7 @@ u8 phonet_address_get(struct net_device *dev, u8 daddr) saddr = find_first_bit(pnd->addrs, 64) << 2; } else saddr = PN_NO_ADDR; - spin_unlock_bh(&pndevs->lock); + rcu_read_unlock(); if (saddr == PN_NO_ADDR) { /* Fallback to another device */ @@ -200,8 +219,8 @@ int phonet_address_lookup(struct net *net, u8 addr) struct phonet_device *pnd; int err = -EADDRNOTAVAIL; - spin_lock_bh(&pndevs->lock); - list_for_each_entry(pnd, &pndevs->list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pnd, &pndevs->list, list) { /* Don't allow unregistering devices! */ if ((pnd->netdev->reg_state != NETREG_REGISTERED) || ((pnd->netdev->flags & IFF_UP)) != IFF_UP) @@ -213,7 +232,7 @@ int phonet_address_lookup(struct net *net, u8 addr) } } found: - spin_unlock_bh(&pndevs->lock); + rcu_read_unlock(); return err; } @@ -304,7 +323,7 @@ static int phonet_init_net(struct net *net) } INIT_LIST_HEAD(&pnn->pndevs.list); - spin_lock_init(&pnn->pndevs.lock); + mutex_init(&pnn->pndevs.lock); mutex_init(&pnn->routes.lock); net_assign_generic(net, phonet_net_id, pnn); return 0; diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c index 609e509b369..2e6c7eb8e76 100644 --- a/net/phonet/pn_netlink.c +++ b/net/phonet/pn_netlink.c @@ -131,8 +131,8 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) int addr_idx = 0, addr_start_idx = cb->args[1]; pndevs = phonet_device_list(sock_net(skb->sk)); - spin_lock_bh(&pndevs->lock); - list_for_each_entry(pnd, &pndevs->list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pnd, &pndevs->list, list) { u8 addr; if (dev_idx > dev_start_idx) @@ -154,7 +154,7 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } out: - spin_unlock_bh(&pndevs->lock); + rcu_read_unlock(); cb->args[0] = dev_idx; cb->args[1] = addr_idx; -- cgit v1.2.3 From 3e5b1101f59fb3e17a8eb32cca100ae07fd7100e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 14 Nov 2009 03:29:38 +0100 Subject: mac80211: reduce the amount of unnecessary traffic on cooked monitor interfaces In order to handle association and authentication in AP mode, hostapd needs access to the tx status info of its own frames through a cooked monitor interface. Without this patch the cooked monitor interfaces also passed on tx status information for packets from other virtual interfaces. This creates a significant performance issue on embedded system. Hostapd tries to work around this by installing a Linux Socket Filter that only captures the frames it's interested in, however data duplication and socket filter matching still uses up enough CPU cycles to be very noticeable on small systems. This patch ensures that tx status information of non-injected frames does not make it to cooked monitor interfaces. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/mac80211/main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index beb8718d905..c74a6a1935b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -587,6 +587,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (!netif_running(sdata->dev)) continue; + if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && + !(info->flags & IEEE80211_TX_CTL_INJECTED) && + (type == IEEE80211_FTYPE_DATA)) + continue; + if (prev_dev) { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { -- cgit v1.2.3 From 3b53fde8ac40c4321389def14d7f4a9e14092fd3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 12:00:37 +0100 Subject: mac80211: let sta_info_get_by_idx get sta by sdata Instead of filtering by device, directly look up by sdata. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 4 ++-- net/mac80211/sta_info.c | 7 ++++--- net/mac80211/sta_info.h | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7f18c8fa188..7d591816ed1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -398,13 +398,13 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; int ret = -ENOENT; rcu_read_lock(); - sta = sta_info_get_by_idx(local, idx, dev); + sta = sta_info_get_by_idx(sdata, idx); if (sta) { ret = 0; memcpy(mac, sta->sta.addr, ETH_ALEN); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 396a94806de..aa017a56afc 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -116,14 +116,15 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr) return sta; } -struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, - struct net_device *dev) +struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, + int idx) { + struct ieee80211_local *local = sdata->local; struct sta_info *sta; int i = 0; list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (dev && dev != sta->sdata->dev) + if (sdata != sta->sdata) continue; if (i < idx) { ++i; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4673454176e..4c84c2205e8 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -409,8 +409,8 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr); /* * Get STA info by index, BROKEN! */ -struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, - struct net_device *dev); +struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, + int idx); /* * Create a new STA info, caller owns returned structure * until sta_info_insert(). -- cgit v1.2.3 From c951ad3550ab40071bb0f222ba6125845769c08a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 12:00:38 +0100 Subject: mac80211: convert aggregation to operate on vifs/stas The entire aggregation code currently operates on the hw pointer and station addresses, but that needs to change to make stations purely per-vif; As one step preparing for that make the aggregation code callable with the station, or by the combination of virtual interface and station address. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 5 +- drivers/net/wireless/ath/ath9k/main.c | 5 +- drivers/net/wireless/ath/ath9k/rc.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + drivers/net/wireless/iwlwifi/iwl-tx.c | 8 +-- include/net/mac80211.h | 28 +++++---- net/mac80211/agg-rx.c | 6 +- net/mac80211/agg-tx.c | 96 ++++++++++++------------------- net/mac80211/driver-ops.h | 5 +- net/mac80211/driver-trace.h | 9 ++- net/mac80211/ht.c | 3 +- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/main.c | 8 +-- 14 files changed, 84 insertions(+), 97 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index bd2a276c870..f9d6db8d013 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2441,6 +2441,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, } static int ar9170_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { @@ -2470,7 +2471,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, tid_info->state = AR9170_TID_STATE_PROGRESS; tid_info->active = false; spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: @@ -2480,7 +2481,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, tid_info->active = false; skb_queue_purge(&tid_info->queue); spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3229c399356..16bdb1b549b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -3078,6 +3078,7 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw) } static int ath9k_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) @@ -3095,11 +3096,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_TX_START: ath_tx_aggr_start(sc, sta, tid, ssn); - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: ath_tx_aggr_stop(sc, sta, tid); - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: ath_tx_aggr_resume(sc, sta, tid); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ea4b9081b4d..1d96777b4cd 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1353,7 +1353,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, an = (struct ath_node *)sta->drv_priv; if(ath_tx_aggr_check(sc, an, tid)) - ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid); + ieee80211_start_tx_ba_session(sta, tid); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 43edd8fd440..2f09e3b7f0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -301,7 +301,7 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); - ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); + ieee80211_start_tx_ba_session(sta, tid); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6385cdf24d1..b80cd0bc584 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2691,6 +2691,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ebfc460115d..f3dff2ecc40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1312,7 +1312,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) if (tid_data->tfds_in_queue == 0) { IWL_DEBUG_HT(priv, "HW queue is empty\n"); tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); + ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid); } else { IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n", tid_data->tfds_in_queue); @@ -1377,7 +1377,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) if (ret) return ret; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); + ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid); return 0; } @@ -1401,7 +1401,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, tx_fifo); tid_data->agg.state = IWL_AGG_OFF; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid); } break; case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -1409,7 +1409,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) if (tid_data->tfds_in_queue == 0) { IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid); } break; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3b3defbe6fc..4af0ffb98aa 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1508,6 +1508,7 @@ struct ieee80211_ops { void (*reset_tsf)(struct ieee80211_hw *hw); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn); @@ -2029,8 +2030,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, /** * ieee80211_start_tx_ba_session - Start a tx Block Ack session. - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @ra: receiver address of the BA session recipient + * @sta: the station for which to start a BA session * @tid: the TID to BA on. * * Return: success if addBA request was sent, failure otherwise @@ -2039,22 +2039,22 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, * the need to start aggregation on a certain RA/TID, the session level * will be managed by the mac80211. */ -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid); +int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid); /** * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * * This function must be called by low level driver once it has * finished with preparations for the BA session. */ -void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); +void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); /** * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * @@ -2062,13 +2062,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); * finished with preparations for the BA session. * This version of the function is IRQ-safe. */ -void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid); /** * ieee80211_stop_tx_ba_session - Stop a Block Ack session. - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @ra: receiver address of the BA session recipient + * @sta: the station whose BA session to stop * @tid: the TID to stop BA. * @initiator: if indicates initiator DELBA frame will be sent. * @@ -2078,24 +2077,23 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, * the need to stop aggregation on a certain RA/TID, the session level * will be managed by the mac80211. */ -int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, - u8 *ra, u16 tid, +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid, enum ieee80211_back_parties initiator); /** * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * * This function must be called by low level driver once it has * finished with preparations for the BA session tear down. */ -void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); +void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); /** * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * @@ -2103,7 +2101,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); * finished with preparations for the BA session tear down. * This version of the function is IRQ-safe. */ -void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid); /** diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index bc064d7933f..f3a5c9e0578 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP, + if (drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_STOP, &sta->sta, tid, NULL)) printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); @@ -284,7 +285,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, goto end; } - ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START, + ret = drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b09948ceec4..6ddd11466df 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -138,7 +138,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP, + ret = drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_TX_STOP, &sta->sta, tid, NULL); /* HW shall not deny going back to legacy */ @@ -196,11 +197,11 @@ static inline int ieee80211_ac_from_tid(int tid) return ieee802_1d_to_ac[tid & 7]; } -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) +int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; u8 *state; int ret = 0; u16 start_seq_num; @@ -208,52 +209,37 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; - if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) + if ((tid >= STA_TID_NUM) || + !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) return -EINVAL; #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", - ra, tid); + pubsta->addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - rcu_read_lock(); - - sta = sta_info_get(local, ra); - if (!sta) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Could not find the station\n"); -#endif - ret = -ENOENT; - goto unlock; - } - /* * The aggregation code is not prepared to handle * anything but STA/AP due to the BSSID handling. * IBSS could work in the code but isn't supported * by drivers or the standard. */ - if (sta->sdata->vif.type != NL80211_IFTYPE_STATION && - sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sta->sdata->vif.type != NL80211_IFTYPE_AP) { - ret = -EINVAL; - goto unlock; - } + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP) + return -EINVAL; if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Suspend in progress. " "Denying BA session request\n"); #endif - ret = -EINVAL; - goto unlock; + return -EINVAL; } spin_lock_bh(&sta->lock); spin_lock(&local->ampdu_lock); - sdata = sta->sdata; - /* we have tried too many times, receiver does not want A-MPDU */ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { ret = -EBUSY; @@ -310,8 +296,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) start_seq_num = sta->tid_seq[tid]; - ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START, - &sta->sta, tid, &start_seq_num); + ret = drv_ampdu_action(local, &sdata->vif, + IEEE80211_AMPDU_TX_START, + pubsta, tid, &start_seq_num); if (ret) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -336,7 +323,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.dialog_token_allocator; sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; - ieee80211_send_addba_request(sta->sdata, ra, tid, + ieee80211_send_addba_request(sdata, pubsta->addr, tid, sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); @@ -348,7 +335,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); #endif - goto unlock; + return 0; err_free: kfree(sta->ampdu_mlme.tid_tx[tid]); @@ -360,8 +347,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) err_unlock_sta: spin_unlock(&local->ampdu_lock); spin_unlock_bh(&sta->lock); - unlock: - rcu_read_unlock(); return ret; } EXPORT_SYMBOL(ieee80211_start_tx_ba_session); @@ -428,13 +413,15 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ieee80211_agg_splice_finish(local, sta, tid); spin_unlock(&local->ampdu_lock); - drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL, + drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_TX_OPERATIONAL, &sta->sta, tid, NULL); } -void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) +void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; u8 *state; @@ -483,10 +470,11 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) } EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); -void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct ieee80211_ra_tid *ra_tid; struct sk_buff *skb = dev_alloc_skb(0); @@ -535,13 +523,12 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, return ret; } -int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, - u8 *ra, u16 tid, +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, enum ieee80211_back_parties initiator) { - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - int ret = 0; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; @@ -549,22 +536,14 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, if (tid >= STA_TID_NUM) return -EINVAL; - rcu_read_lock(); - sta = sta_info_get(local, ra); - if (!sta) { - rcu_read_unlock(); - return -ENOENT; - } - - ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator); - rcu_read_unlock(); - return ret; + return __ieee80211_stop_tx_ba_session(sta, tid, initiator); } EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); -void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) +void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; u8 *state; @@ -627,10 +606,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) } EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); -void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct ieee80211_ra_tid *ra_tid; struct sk_buff *skb = dev_alloc_skb(0); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 020a94a3110..921dd9c9ff6 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -239,15 +239,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) } static inline int drv_ampdu_action(struct ieee80211_local *local, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { int ret = -EOPNOTSUPP; if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(&local->hw, action, + ret = local->ops->ampdu_action(&local->hw, vif, action, sta, tid, ssn); - trace_drv_ampdu_action(local, action, sta, tid, ssn, ret); + trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret); return ret; } diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 37b9051afcf..b8fef1d1136 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -634,11 +634,12 @@ TRACE_EVENT(drv_tx_last_beacon, TRACE_EVENT(drv_ampdu_action, TP_PROTO(struct ieee80211_local *local, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, int ret), - TP_ARGS(local, action, sta, tid, ssn, ret), + TP_ARGS(local, vif, action, sta, tid, ssn, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -647,10 +648,12 @@ TRACE_EVENT(drv_ampdu_action, __field(u16, tid) __field(u16, ssn) __field(int, ret) + VIF_ENTRY ), TP_fast_assign( LOCAL_ASSIGN; + VIF_ASSIGN; STA_ASSIGN; __entry->ret = ret; __entry->action = action; @@ -659,8 +662,8 @@ TRACE_EVENT(drv_ampdu_action, ), TP_printk( - LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", - LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret ) ); #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 48ef1a282b9..345c8ee5017 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -141,7 +141,6 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_local *local = sdata->local; u16 tid, params; u16 initiator; @@ -164,7 +163,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, sta->ampdu_mlme.tid_state_tx[tid] = HT_AGG_STATE_OPERATIONAL; spin_unlock_bh(&sta->lock); - ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid, + ieee80211_stop_tx_ba_session(&sta->sta, tid, WLAN_BACK_RECIPIENT); } } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b63b99fb2fd..b7598db5ade 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -771,8 +771,9 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) return netdev_priv(dev); } -/* this struct represents 802.11n's RA/TID combination */ +/* this struct represents 802.11n's RA/TID combination along with our vif */ struct ieee80211_ra_tid { + struct ieee80211_vif *vif; u8 ra[ETH_ALEN]; u16 tid; }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c74a6a1935b..f4be97c3b74 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -296,14 +296,14 @@ static void ieee80211_tasklet_handler(unsigned long data) break; case IEEE80211_DELBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_stop_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); + ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra, + ra_tid->tid); dev_kfree_skb(skb); break; case IEEE80211_ADDBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_start_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); + ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra, + ra_tid->tid); dev_kfree_skb(skb); break ; default: -- cgit v1.2.3 From af2ced6a32dafb71d21b726c06df57fc574093d7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 12:00:39 +0100 Subject: mac80211: push michael MIC report after DA check When we receive a michael MIC failure report from the hardware we currently do not check whether it is actually reported on a frame that is destined to us. It shouldn't be possible to get a michael MIC failure report on other frames, but it also doesn't hurt to verify. Also, since we then don't need the station struct that early, move looking it up a bit later in the RX path. Finally, while at it, a few code cleanups in the area. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6bce97ee253..68d9e9c8659 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1818,11 +1818,11 @@ static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, * Some hardware seem to generate incorrect Michael MIC * reports; ignore them to avoid triggering countermeasures. */ - goto ignore; + return; } if (!ieee80211_has_protected(hdr->frame_control)) - goto ignore; + return; if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) { /* @@ -1831,18 +1831,15 @@ static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, * group keys and only the AP is sending real multicast * frames in the BSS. */ - goto ignore; + return; } if (!ieee80211_is_data(hdr->frame_control) && !ieee80211_is_auth(hdr->frame_control)) - goto ignore; + return; mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, GFP_ATOMIC); - ignore: - dev_kfree_skb(rx->skb); - rx->skb = NULL; } /* TODO: use IEEE80211_RX_FRAGMENTED */ @@ -2064,8 +2061,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, return 0; break; case NL80211_IFTYPE_MONITOR: - /* take everything */ - break; case NL80211_IFTYPE_UNSPECIFIED: case __NL80211_IFTYPE_AFTER_LAST: /* should never get here */ @@ -2097,24 +2092,12 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; - rx.status = status; rx.rate = rate; if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control)) local->dot11ReceivedFragmentCount++; - rx.sta = sta_info_get(local, hdr->addr2); - if (rx.sta) { - rx.sdata = rx.sta->sdata; - rx.dev = rx.sta->sdata->dev; - } - - if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(hdr, &rx); - return; - } - if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || test_bit(SCAN_OFF_CHANNEL, &local->scanning))) rx.flags |= IEEE80211_RX_IN_SCAN; @@ -2122,13 +2105,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_parse_qos(&rx); ieee80211_verify_alignment(&rx); - skb = rx.skb; + rx.sta = sta_info_get(local, hdr->addr2); + if (rx.sta) { + rx.sdata = rx.sta->sdata; + rx.dev = rx.sta->sdata->dev; + } if (rx.sdata && ieee80211_is_data(hdr->frame_control)) { rx.flags |= IEEE80211_RX_RA_MATCH; prepares = prepare_for_handlers(rx.sdata, &rx, hdr); - if (prepares) - prev = rx.sdata; + if (prepares) { + if (status->flag & RX_FLAG_MMIC_ERROR) { + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, &rx); + } else + prev = rx.sdata; + } } else list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!netif_running(sdata->dev)) continue; @@ -2143,6 +2135,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (!prepares) continue; + if (status->flag & RX_FLAG_MMIC_ERROR) { + rx.sdata = sdata; + if (rx.flags & IEEE80211_RX_RA_MATCH) + ieee80211_rx_michael_mic_report(hdr, &rx); + continue; + } + /* * frame is destined for this interface, but if it's not * also for the previous one we handle that after the -- cgit v1.2.3 From a02ae758e8780d737b6d0135d6292bb3043e7eea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 12:00:40 +0100 Subject: mac80211: cleanup reorder buffer handling The reorder buffer handling is written in a quite peculiar style (especially comments) and also has a quirk where it invokes the entire reorder code in ieee80211_sta_manage_reorder_buf() for just a handful of lines in it with a special argument. Split out ieee80211_release_reorder_frames which can then be invoked from BAR handling and other reordering code, clean up code and comments and remove function arguments that are now unused from ieee80211_sta_manage_reorder_buf(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 162 +++++++++++++++++++++++++++--------------------------- 1 file changed, 81 insertions(+), 81 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 68d9e9c8659..37e9891605b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -27,11 +27,10 @@ #include "tkip.h" #include "wme.h" -static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - struct sk_buff *skb, - u16 mpdu_seq_num, - int bar_req); +static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + u16 head_seq_num); + /* * monitor mode reception * @@ -1592,11 +1591,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) if (ieee80211_is_back_req(bar->frame_control)) { if (!rx->sta) - return RX_CONTINUE; + return RX_DROP_MONITOR; tid = le16_to_cpu(bar->control) >> 12; if (rx->sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) - return RX_CONTINUE; + return RX_DROP_MONITOR; tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; @@ -1606,13 +1605,10 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(tid_agg_rx->timeout)); - /* manage reordering buffer according to requested */ - /* sequence number */ - rcu_read_lock(); - ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, - start_seq_num, 1); - rcu_read_unlock(); - return RX_DROP_UNUSABLE; + /* release stored frames up to start of BAR */ + ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); + kfree_skb(skb); + return RX_QUEUED; } return RX_CONTINUE; @@ -2223,6 +2219,18 @@ no_frame: tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); } +static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + u16 head_seq_num) +{ + int index; + + while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { + index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % + tid_agg_rx->buf_size; + ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + } +} /* * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If @@ -2234,15 +2242,17 @@ no_frame: #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) /* - * As it function blongs to Rx path it must be called with - * the proper rcu_read_lock protection for its flow. + * As this function belongs to the RX path it must be under + * rcu_read_lock protection. It returns false if the frame + * can be processed immediately, true if it was consumed. */ -static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - struct sk_buff *skb, - u16 mpdu_seq_num, - int bar_req) +static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + struct sk_buff *skb) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 sc = le16_to_cpu(hdr->seq_ctrl); + u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; u16 head_seq_num, buf_size; int index; @@ -2252,47 +2262,37 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* frame with out of date sequence number */ if (seq_less(mpdu_seq_num, head_seq_num)) { dev_kfree_skb(skb); - return 1; + return true; } - /* if frame sequence number exceeds our buffering window size or - * block Ack Request arrived - release stored frames */ - if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) { - /* new head to the ordering buffer */ - if (bar_req) - head_seq_num = mpdu_seq_num; - else - head_seq_num = - seq_inc(seq_sub(mpdu_seq_num, buf_size)); + /* + * If frame the sequence number exceeds our buffering window + * size release some previous frames to make room for this one. + */ + if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { + head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); /* release stored frames up to new head to stack */ - while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { - index = seq_sub(tid_agg_rx->head_seq_num, - tid_agg_rx->ssn) - % tid_agg_rx->buf_size; - ieee80211_release_reorder_frame(hw, tid_agg_rx, - index); - } - if (bar_req) - return 1; + ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); } - /* now the new frame is always in the range of the reordering */ - /* buffer window */ - index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) - % tid_agg_rx->buf_size; + /* Now the new frame is always in the range of the reordering buffer */ + + index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; + /* check if we already stored this frame */ if (tid_agg_rx->reorder_buf[index]) { dev_kfree_skb(skb); - return 1; + return true; } - /* if arrived mpdu is in the right order and nothing else stored */ - /* release it immediately */ + /* + * If the current MPDU is in the right order and nothing else + * is stored we can process it directly, no need to buffer it. + */ if (mpdu_seq_num == tid_agg_rx->head_seq_num && - tid_agg_rx->stored_mpdu_num == 0) { - tid_agg_rx->head_seq_num = - seq_inc(tid_agg_rx->head_seq_num); - return 0; + tid_agg_rx->stored_mpdu_num == 0) { + tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); + return false; } /* put the frame in the reordering buffer */ @@ -2300,8 +2300,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, tid_agg_rx->reorder_time[index] = jiffies; tid_agg_rx->stored_mpdu_num++; /* release the buffer until next missing frame */ - index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) - % tid_agg_rx->buf_size; + index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % + tid_agg_rx->buf_size; if (!tid_agg_rx->reorder_buf[index] && tid_agg_rx->stored_mpdu_num > 1) { /* @@ -2312,12 +2312,12 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, int skipped = 1; for (j = (index + 1) % tid_agg_rx->buf_size; j != index; j = (j + 1) % tid_agg_rx->buf_size) { - if (tid_agg_rx->reorder_buf[j] == NULL) { + if (!tid_agg_rx->reorder_buf[j]) { skipped++; continue; } if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + - HZ / 10)) + HT_RX_REORDER_BUF_TIMEOUT)) break; #ifdef CONFIG_MAC80211_HT_DEBUG @@ -2333,51 +2333,56 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, * Increment the head seq# also for the skipped slots. */ tid_agg_rx->head_seq_num = - (tid_agg_rx->head_seq_num + skipped) & - SEQ_MASK; + (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; skipped = 0; } } else while (tid_agg_rx->reorder_buf[index]) { ieee80211_release_reorder_frame(hw, tid_agg_rx, index); - index = seq_sub(tid_agg_rx->head_seq_num, - tid_agg_rx->ssn) % tid_agg_rx->buf_size; + index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % + tid_agg_rx->buf_size; } - return 1; + + return true; } -static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, - struct sk_buff *skb) +/* + * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns + * true if the MPDU was buffered, false if it should be processed. + */ +static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, + struct sk_buff *skb) { struct ieee80211_hw *hw = &local->hw; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct sta_info *sta; struct tid_ampdu_rx *tid_agg_rx; u16 sc; - u16 mpdu_seq_num; - u8 ret = 0; int tid; + if (!ieee80211_is_data_qos(hdr->frame_control)) + return false; + + /* + * filter the QoS data rx stream according to + * STA/TID and check if this STA/TID is on aggregation + */ + sta = sta_info_get(local, hdr->addr2); if (!sta) - return ret; - - /* filter the QoS data rx stream according to - * STA/TID and check if this STA/TID is on aggregation */ - if (!ieee80211_is_data_qos(hdr->frame_control)) - goto end_reorder; + return false; tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) - goto end_reorder; + return false; tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; /* qos null data frames are excluded */ if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) - goto end_reorder; + return false; - /* new un-ordered ampdu frame - process it */ + /* new, potentially un-ordered, ampdu frame - process it */ /* reset session timer */ if (tid_agg_rx->timeout) @@ -2389,16 +2394,11 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, if (sc & IEEE80211_SCTL_FRAG) { ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); - ret = 1; - goto end_reorder; + dev_kfree_skb(skb); + return true; } - /* according to mpdu sequence number deal with reordering buffer */ - mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; - ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, - mpdu_seq_num, 0); - end_reorder: - return ret; + return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb); } /* -- cgit v1.2.3 From eb9fb5b8883535c27d2cc5d4e4dbab3532f97b18 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 13:58:20 +0100 Subject: mac80211: trim RX data The RX data contains the netdev, which is duplicated since we have the sdata, and the RX status pointer, which is duplicate since we have the skb. Remove those two fields to have fewer fields that depend on each other and simply load them as necessary. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/rx.c | 80 ++++++++++++++++++++++++---------------------- net/mac80211/wep.c | 8 +++-- net/mac80211/wpa.c | 25 ++++++++------- 4 files changed, 61 insertions(+), 54 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b7598db5ade..c612981fc23 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -167,12 +167,10 @@ typedef unsigned __bitwise__ ieee80211_rx_result; struct ieee80211_rx_data { struct sk_buff *skb; - struct net_device *dev; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; struct sta_info *sta; struct ieee80211_key *key; - struct ieee80211_rx_status *status; struct ieee80211_rate *rate; unsigned int flags; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 37e9891605b..904aaea081c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -477,7 +477,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); - char *dev_addr = rx->dev->dev_addr; + char *dev_addr = rx->sdata->dev->dev_addr; if (ieee80211_is_data(hdr->frame_control)) { if (is_multicast_ether_addr(hdr->addr1)) { @@ -591,7 +591,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; int keyidx; int hdrlen; ieee80211_rx_result result = RX_DROP_UNUSABLE; @@ -645,8 +647,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; } else if (mmie_keyidx >= 0) { /* Broadcast/multicast robust management frame / BIP */ - if ((rx->status->flag & RX_FLAG_DECRYPTED) && - (rx->status->flag & RX_FLAG_IV_STRIPPED)) + if ((status->flag & RX_FLAG_DECRYPTED) && + (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; if (mmie_keyidx < NUM_DEFAULT_KEYS || @@ -678,8 +680,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) * we somehow allow the driver to tell us which key * the hardware used if this flag is set? */ - if ((rx->status->flag & RX_FLAG_DECRYPTED) && - (rx->status->flag & RX_FLAG_IV_STRIPPED)) + if ((status->flag & RX_FLAG_DECRYPTED) && + (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -715,8 +717,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) /* Check for weak IVs if possible */ if (rx->sta && rx->key->conf.alg == ALG_WEP && ieee80211_is_data(hdr->frame_control) && - (!(rx->status->flag & RX_FLAG_IV_STRIPPED) || - !(rx->status->flag & RX_FLAG_DECRYPTED)) && + (!(status->flag & RX_FLAG_IV_STRIPPED) || + !(status->flag & RX_FLAG_DECRYPTED)) && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; @@ -736,7 +738,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) } /* either the frame has been decrypted or will be dropped */ - rx->status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_DECRYPTED; return result; } @@ -816,7 +818,9 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) { struct sta_info *sta = rx->sta; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (!sta) return RX_CONTINUE; @@ -847,8 +851,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; - sta->last_signal = rx->status->signal; - sta->last_noise = rx->status->noise; + sta->last_signal = status->signal; + sta->last_noise = status->noise; /* * Change STA power saving mode only at the end of a frame @@ -1140,11 +1144,14 @@ ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) { + struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + /* * Pass through unencrypted frames if the hardware has * decrypted them already. */ - if (rx->status->flag & RX_FLAG_DECRYPTED) + if (status->flag & RX_FLAG_DECRYPTED) return 0; /* Drop unencrypted frames if key is set. */ @@ -1178,8 +1185,8 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) static int __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) { - struct net_device *dev = rx->dev; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr && @@ -1205,7 +1212,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) * of whether the frame was encrypted or not. */ if (ehdr->h_proto == htons(ETH_P_PAE) && - (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 || + (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 || compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) return true; @@ -1222,10 +1229,10 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) static void ieee80211_deliver_skb(struct ieee80211_rx_data *rx) { - struct net_device *dev = rx->dev; + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct net_device *dev = sdata->dev; struct ieee80211_local *local = rx->local; struct sk_buff *skb, *xmit_skb; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; struct sta_info *dsta; @@ -1306,7 +1313,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) { - struct net_device *dev = rx->dev; + struct net_device *dev = rx->sdata->dev; struct ieee80211_local *local = rx->local; u16 ethertype; u8 *payload; @@ -1431,12 +1438,11 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) unsigned int hdrlen; struct sk_buff *skb = rx->skb, *fwd_skb; struct ieee80211_local *local = rx->local; - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = rx->sdata; hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); - sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if (!ieee80211_is_data(hdr->frame_control)) return RX_CONTINUE; @@ -1474,7 +1480,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* Frame has reached destination. Don't forward */ if (!is_multicast_ether_addr(hdr->addr1) && - compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) + compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0) return RX_CONTINUE; mesh_hdr->ttl--; @@ -1491,10 +1497,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) if (!fwd_skb && net_ratelimit()) printk(KERN_DEBUG "%s: failed to clone mesh frame\n", - rx->dev->name); + sdata->dev->name); fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; - memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); + memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN); info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; @@ -1528,7 +1534,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } if (is_multicast_ether_addr(hdr->addr1) || - rx->dev->flags & IFF_PROMISC) + sdata->dev->flags & IFF_PROMISC) return RX_CONTINUE; else return RX_DROP_MONITOR; @@ -1538,9 +1544,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { - struct net_device *dev = rx->dev; + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); __le16 fc = hdr->frame_control; int err; @@ -1664,7 +1670,7 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_action(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); + struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; int len = rx->skb->len; @@ -1776,7 +1782,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); + struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; if (!(rx->flags & IEEE80211_RX_RA_MATCH)) @@ -1852,7 +1858,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) } __attribute__ ((packed)) *rthdr; struct sk_buff *skb = rx->skb, *skb2; struct net_device *prev_dev = NULL; - struct ieee80211_rx_status *status = rx->status; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); if (rx->flags & IEEE80211_RX_CMNTR_REPORTED) goto out_free_skb; @@ -1928,7 +1934,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, rx->skb = skb; rx->sdata = sdata; - rx->dev = sdata->dev; #define CALL_RXH(rxh) \ do { \ @@ -1987,7 +1992,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_data *rx, struct ieee80211_hdr *hdr) { - u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type); + struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); int multicast = is_multicast_ether_addr(hdr->addr1); switch (sdata->vif.type) { @@ -2019,10 +2026,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!rx->sta) { int rate_idx; - if (rx->status->flag & RX_FLAG_HT) + if (status->flag & RX_FLAG_HT) rate_idx = 0; /* TODO: HT rates */ else - rate_idx = rx->status->rate_idx; + rate_idx = status->rate_idx; rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, BIT(rate_idx)); } @@ -2088,7 +2095,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; - rx.status = status; rx.rate = rate; if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control)) @@ -2102,10 +2108,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_verify_alignment(&rx); rx.sta = sta_info_get(local, hdr->addr2); - if (rx.sta) { + if (rx.sta) rx.sdata = rx.sta->sdata; - rx.dev = rx.sta->sdata->dev; - } if (rx.sdata && ieee80211_is_data(hdr->frame_control)) { rx.flags |= IEEE80211_RX_RA_MATCH; diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 8a980f13694..247123fe1a7 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -281,16 +281,18 @@ bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; + struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (!ieee80211_is_data(hdr->frame_control) && !ieee80211_is_auth(hdr->frame_control)) return RX_CONTINUE; - if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { + if (!(status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) return RX_DROP_UNUSABLE; - } else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) { + } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 70778694877..5332014cb22 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -85,16 +85,16 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) u8 *data, *key = NULL, key_offset; size_t data_len; unsigned int hdrlen; - struct ieee80211_hdr *hdr; u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; int authenticator = 1, wpa_test = 0; /* No way to verify the MIC if the hardware stripped it */ - if (rx->status->flag & RX_FLAG_MMIC_STRIPPED) + if (status->flag & RX_FLAG_MMIC_STRIPPED) return RX_CONTINUE; - hdr = (struct ieee80211_hdr *)skb->data; if (!rx->key || rx->key->conf.alg != ALG_TKIP || !ieee80211_has_protected(hdr->frame_control) || !ieee80211_is_data_present(hdr->frame_control)) @@ -216,6 +216,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) int hdrlen, res, hwaccel = 0, wpa_test = 0; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -225,8 +226,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) if (!rx->sta || skb->len - hdrlen < 12) return RX_DROP_UNUSABLE; - if (rx->status->flag & RX_FLAG_DECRYPTED) { - if (rx->status->flag & RX_FLAG_IV_STRIPPED) { + if (status->flag & RX_FLAG_DECRYPTED) { + if (status->flag & RX_FLAG_IV_STRIPPED) { /* * Hardware took care of all processing, including * replay protection, and stripped the ICV/IV so @@ -442,6 +443,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) int hdrlen; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); u8 pn[CCMP_PN_LEN]; int data_len; @@ -455,8 +457,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) if (!rx->sta || data_len < 0) return RX_DROP_UNUSABLE; - if ((rx->status->flag & RX_FLAG_DECRYPTED) && - (rx->status->flag & RX_FLAG_IV_STRIPPED)) + if ((status->flag & RX_FLAG_DECRYPTED) && + (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; ccmp_hdr2pn(pn, skb->data + hdrlen); @@ -466,7 +468,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; } - if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { + if (!(status->flag & RX_FLAG_DECRYPTED)) { /* hardware didn't decrypt/verify MIC */ ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1); @@ -563,6 +565,7 @@ ieee80211_rx_result ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) { struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_key *key = rx->key; struct ieee80211_mmie *mmie; u8 aad[20], mic[8], ipn[6]; @@ -571,8 +574,8 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) if (!ieee80211_is_mgmt(hdr->frame_control)) return RX_CONTINUE; - if ((rx->status->flag & RX_FLAG_DECRYPTED) && - (rx->status->flag & RX_FLAG_IV_STRIPPED)) + if ((status->flag & RX_FLAG_DECRYPTED) && + (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; if (skb->len < 24 + sizeof(*mmie)) @@ -591,7 +594,7 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; } - if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { + if (!(status->flag & RX_FLAG_DECRYPTED)) { /* hardware didn't decrypt/verify MIC */ bip_aad(skb, aad); ieee80211_aes_cmac(key->u.aes_cmac.tfm, -- cgit v1.2.3 From 5f0b7de59fae1e57b2481c9756cd4a0f6308530f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 13:58:21 +0100 Subject: mac80211: improve rate handling Some code currently assumes that there's a valid rate pointer even in the HT case, but there can't be. To reduce reliance on that, remove the rate pointer from the RX data struct and pass it where it's needed. Also, for now, in radiotap announce HT frames as having a DYN channel type, and remove their rate from cooked monitor radiotap completely (it isn't present in the regular monitor radiotap either.) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/rx.c | 35 ++++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c612981fc23..a1bd4b2bc9e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -171,7 +171,6 @@ struct ieee80211_rx_data { struct ieee80211_sub_if_data *sdata; struct sta_info *sta; struct ieee80211_key *key; - struct ieee80211_rate *rate; unsigned int flags; int queue; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 904aaea081c..e0cb3357f79 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -163,6 +163,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->band == IEEE80211_BAND_5GHZ) put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, pos); + else if (status->flag & RX_FLAG_HT) + put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, + pos); else if (rate->flags & IEEE80211_RATE_ERP_G) put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, pos); @@ -1845,14 +1848,15 @@ static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, } /* TODO: use IEEE80211_RX_FRAGMENTED */ -static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) +static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, + struct ieee80211_rate *rate) { struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = rx->local; struct ieee80211_rtap_hdr { struct ieee80211_radiotap_header hdr; u8 flags; - u8 rate; + u8 rate_or_pad; __le16 chan_freq; __le16 chan_flags; } __attribute__ ((packed)) *rthdr; @@ -1872,10 +1876,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); rthdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL)); - rthdr->rate = rx->rate->bitrate / 5; + if (rate) { + rthdr->rate_or_pad = rate->bitrate / 5; + rthdr->hdr.it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); + } rthdr->chan_freq = cpu_to_le16(status->freq); if (status->band == IEEE80211_BAND_5GHZ) @@ -1928,7 +1935,8 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_data *rx, - struct sk_buff *skb) + struct sk_buff *skb, + struct ieee80211_rate *rate) { ieee80211_rx_result res = RX_DROP_MONITOR; @@ -1972,7 +1980,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, rx->sta->rx_dropped++; /* fall through */ case RX_CONTINUE: - ieee80211_rx_cooked_monitor(rx); + ieee80211_rx_cooked_monitor(rx, rate); break; case RX_DROP_UNUSABLE: I802_DEBUG_INC(sdata->local->rx_handlers_drop); @@ -2095,7 +2103,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; - rx.rate = rate; if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control)) local->dot11ReceivedFragmentCount++; @@ -2167,11 +2174,11 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, prev->dev->name); continue; } - ieee80211_invoke_rx_handlers(prev, &rx, skb_new); + ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); prev = sdata; } if (prev) - ieee80211_invoke_rx_handlers(prev, &rx, skb); + ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); else dev_kfree_skb(skb); } @@ -2200,7 +2207,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, int index) { struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; + struct ieee80211_rate *rate = NULL; struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; struct ieee80211_rx_status *status; @@ -2211,9 +2218,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, /* release the reordered frames to stack */ sband = hw->wiphy->bands[status->band]; - if (status->flag & RX_FLAG_HT) - rate = sband->bitrates; /* TODO: HT rates */ - else + if (!(status->flag & RX_FLAG_HT)) rate = &sband->bitrates[status->rate_idx]; __ieee80211_rx_handle_packet(hw, skb, rate); tid_agg_rx->stored_mpdu_num--; @@ -2460,10 +2465,6 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) status->rate_idx, status->rate_idx)) goto drop; - /* HT rates are not in the table - use the highest legacy rate - * for now since other parts of mac80211 may not yet be fully - * MCS aware. */ - rate = &sband->bitrates[sband->n_bitrates - 1]; } else { if (WARN_ON(status->rate_idx < 0 || status->rate_idx >= sband->n_bitrates)) -- cgit v1.2.3 From d84f323477260e773d5317ad7cbe50f76115cb47 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 23:20:41 +0100 Subject: mac80211: remove dev_hold/put calls If we move the rcu sections a little, there's no need to touch the device refcount. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3ad053f6de1..375cecc837a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1430,8 +1430,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, int headroom; bool may_encrypt; - dev_hold(sdata->dev); - if (need_dynamic_ps(local)) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, @@ -1446,6 +1444,8 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + rcu_read_lock(); + if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; @@ -1468,7 +1468,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, * support we will need a different mechanism. */ - rcu_read_lock(); list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) { if (!netif_running(tmp_sdata->dev)) @@ -1477,13 +1476,10 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, continue; if (compare_ether_addr(tmp_sdata->dev->dev_addr, hdr->addr2) == 0) { - dev_hold(tmp_sdata->dev); - dev_put(sdata->dev); sdata = tmp_sdata; break; } } - rcu_read_unlock(); } } @@ -1497,7 +1493,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) { dev_kfree_skb(skb); - dev_put(sdata->dev); + rcu_read_unlock(); return; } @@ -1508,13 +1504,13 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, !is_multicast_ether_addr(hdr->addr1)) if (mesh_nexthop_lookup(skb, sdata)) { /* skb queued: don't free */ - dev_put(sdata->dev); + rcu_read_unlock(); return; } ieee80211_select_queue(local, skb); ieee80211_tx(sdata, skb, false); - dev_put(sdata->dev); + rcu_read_unlock(); } netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, @@ -1964,12 +1960,10 @@ void ieee80211_tx_pending(unsigned long data) } sdata = vif_to_sdata(info->control.vif); - dev_hold(sdata->dev); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); txok = ieee80211_tx_pending_skb(local, skb); - dev_put(sdata->dev); if (!txok) __skb_queue_head(&local->pending[i], skb); spin_lock_irqsave(&local->queue_stop_reason_lock, -- cgit v1.2.3 From 15ff63653e507ec928a4a4386405a82446e096b1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Nov 2009 13:34:04 +0100 Subject: mac80211: use fixed broadcast address The netdev broadcast address cannot change from all-ones so there's no need to use it; we can instead hard-code it. Since we already have an instance in tkip.c, which will be shared if it is marked static const, doing this reduces text size at no data/bss cost. The real motivation for this is, of course, the desire to get rid of almost all uses of netdevs in mac80211 so that auditing their use becomes easier. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 5 +++-- net/mac80211/mesh.h | 4 ++-- net/mac80211/mesh_hwmp.c | 20 +++++++++++--------- net/mac80211/mesh_pathtbl.c | 3 ++- net/mac80211/tkip.c | 4 ++-- net/mac80211/tx.c | 10 +++++++--- 6 files changed, 27 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index bbd56b08789..3a0683ba357 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -394,8 +394,9 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) * * Return the length of the 802.11 (does not include a mesh control header) */ -int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char - *meshda, char *meshsa) { +int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, + const u8 *meshda, const u8 *meshsa) +{ if (is_multicast_ether_addr(meshda)) { *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA TA SA */ diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index bd0e1cbb9a1..31e10254186 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -220,7 +220,7 @@ struct mesh_rmc { /* Public interfaces */ /* Various */ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, - char *da, char *sa); + const u8 *da, const u8 *sa); int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, struct ieee80211_sub_if_data *sdata, char *addr4, char *addr5, char *addr6); @@ -284,7 +284,7 @@ u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl); /* Mesh paths */ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, - u8 *ra, struct ieee80211_sub_if_data *sdata); + const u8 *ra, struct ieee80211_sub_if_data *sdata); void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); void mesh_path_flush_pending(struct mesh_path *mpath); void mesh_path_tx_pending(struct mesh_path *mpath); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 5c67e7b8790..d93019874e4 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -101,10 +101,12 @@ enum mpath_frame_type { MPATH_RANN }; +static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target, - __le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime, - __le32 metric, __le32 preq_id, + __le32 target_sn, const u8 *da, u8 hop_count, u8 ttl, + __le32 lifetime, __le32 metric, __le32 preq_id, struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; @@ -198,8 +200,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, * @ra: node this frame is addressed to */ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, - __le16 target_rcode, u8 *ra, - struct ieee80211_sub_if_data *sdata) + __le16 target_rcode, const u8 *ra, + struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); @@ -548,7 +550,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, cpu_to_le32(orig_sn), target_flags, target_addr, - cpu_to_le32(target_sn), sdata->dev->broadcast, + cpu_to_le32(target_sn), broadcast_addr, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); @@ -660,7 +662,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, spin_unlock_bh(&mpath->state_lock); mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), cpu_to_le16(target_rcode), - sdata->dev->broadcast, sdata); + broadcast_addr, sdata); } else spin_unlock_bh(&mpath->state_lock); } @@ -709,7 +711,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, if (mpath->sn < orig_sn) { mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, cpu_to_le32(orig_sn), - 0, NULL, 0, sdata->dev->broadcast, + 0, NULL, 0, broadcast_addr, hopcount, ttl, 0, cpu_to_le32(metric + mpath->metric), 0, sdata); @@ -890,7 +892,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) spin_unlock_bh(&mpath->state_lock); mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, - cpu_to_le32(mpath->sn), sdata->dev->broadcast, 0, + cpu_to_le32(mpath->sn), broadcast_addr, 0, ttl, cpu_to_le32(lifetime), 0, cpu_to_le32(ifmsh->preq_id++), sdata); mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); @@ -1011,6 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr, cpu_to_le32(++ifmsh->sn), - 0, NULL, 0, sdata->dev->broadcast, + 0, NULL, 0, broadcast_addr, 0, MESH_TTL, 0, 0, 0, sdata); } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 5399e7a9ec6..3fbabbf34ea 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -449,6 +449,7 @@ err_path_alloc: */ void mesh_plink_broken(struct sta_info *sta) { + static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; struct mesh_path *mpath; struct mpath_node *node; struct hlist_node *p; @@ -468,7 +469,7 @@ void mesh_plink_broken(struct sta_info *sta) mesh_path_error_tx(MESH_TTL, mpath->dst, cpu_to_le32(mpath->sn), PERR_RCODE_DEST_UNREACH, - sdata->dev->broadcast, sdata); + bcast, sdata); } else spin_unlock_bh(&mpath->state_lock); } diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 964b7faa7f1..4921d724b6c 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -301,9 +301,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, #endif if (key->local->ops->update_tkip_key && key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - u8 bcast[ETH_ALEN] = + static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - u8 *sta_addr = key->sta->sta.addr; + const u8 *sta_addr = key->sta->sta.addr; if (is_multicast_ether_addr(ra)) sta_addr = bcast; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 375cecc837a..3466e1f7fd1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1683,21 +1683,25 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, /* packet from other interface */ struct mesh_path *mppath; int is_mesh_mcast = 1; - char *mesh_da; + const u8 *mesh_da; rcu_read_lock(); if (is_multicast_ether_addr(skb->data)) /* DA TA mSA AE:SA */ mesh_da = skb->data; else { + static const u8 bcast[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + mppath = mpp_path_lookup(skb->data, sdata); if (mppath) { /* RA TA mDA mSA AE:DA SA */ mesh_da = mppath->mpp; is_mesh_mcast = 0; - } else + } else { /* DA TA mSA AE:SA */ - mesh_da = dev->broadcast; + mesh_da = bcast; + } } hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, mesh_da, dev->dev_addr); -- cgit v1.2.3 From af65cd96dd4ea8ea5adc6ee850e61a407cd1067a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Nov 2009 18:18:36 +0100 Subject: mac80211: make software rate control optional Some devices implement the entire rate control in firmware in some way, like wl1271 or like iwlwifi which does some things in software but not a lot. Therefore generic software rate control is rather useless for them and just adds avoidable overhead to the transmit path. It's fairly simple to let drivers indicate that they do not need rate control, but they need to fulfil a number of conditions that we encode in WARN_ONs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 14 ++++++++++++++ net/mac80211/debugfs.c | 2 +- net/mac80211/rate.c | 12 +++++++++++- net/mac80211/rate.h | 9 ++++++--- net/mac80211/sta_info.c | 29 ++++++++++++++++++++++------- net/mac80211/tx.c | 3 ++- 6 files changed, 56 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4af0ffb98aa..f34f4ca7016 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -855,6 +855,19 @@ enum ieee80211_tkip_key_type { * any particular flags. There are some exceptions to this rule, * however, so you are advised to review these flags carefully. * + * @IEEE80211_HW_HAS_RATE_CONTROL: + * The hardware or firmware includes rate control, and cannot be + * controlled by the stack. As such, no rate control algorithm + * should be instantiated, and the TX rate reported to userspace + * will be taken from the TX status instead of the rate control + * algorithm. + * Note that this requires that the driver implement a number of + * callbacks so it has the correct information, it needs to have + * the @set_rts_threshold callback and must look at the BSS config + * @use_cts_prot for G/N protection, @use_short_slot for slot + * timing in 2.4 GHz and @use_short_preamble for preambles for + * CCK frames. + * * @IEEE80211_HW_RX_INCLUDES_FCS: * Indicates that received frames passed to the stack include * the FCS at the end. @@ -913,6 +926,7 @@ enum ieee80211_tkip_key_type { * avoid waking up cpu. */ enum ieee80211_hw_flags { + IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 82c807723b6..e4b54093d41 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -52,7 +52,7 @@ DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", local->wep_iv & 0xffffff); DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", - local->rate_ctrl ? local->rate_ctrl->ops->name : ""); + local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); static ssize_t tsf_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index ccda7454fb1..b9007f80cb9 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -284,9 +284,16 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, struct rate_control_ref *ref, *old; ASSERT_RTNL(); + if (local->open_count) return -EBUSY; + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { + if (WARN_ON(!local->ops->set_rts_threshold)) + return -EINVAL; + return 0; + } + ref = rate_control_alloc(name, local); if (!ref) { printk(KERN_WARNING "%s: Failed to select rate control " @@ -305,7 +312,6 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, "algorithm '%s'\n", wiphy_name(local->hw.wiphy), ref->ops->name); - return 0; } @@ -314,6 +320,10 @@ void rate_control_deinitialize(struct ieee80211_local *local) struct rate_control_ref *ref; ref = local->rate_ctrl; + + if (!ref) + return; + local->rate_ctrl = NULL; rate_control_put(ref); } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 2ab5ad9e71c..cb9bd1f65e2 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -59,6 +59,9 @@ static inline void rate_control_rate_init(struct sta_info *sta) void *priv_sta = sta->rate_ctrl_priv; struct ieee80211_supported_band *sband; + if (!ref) + return; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; ref->ops->rate_init(ref->priv, sband, ista, priv_sta); @@ -72,7 +75,7 @@ static inline void rate_control_rate_update(struct ieee80211_local *local, struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; - if (ref->ops->rate_update) + if (ref && ref->ops->rate_update) ref->ops->rate_update(ref->priv, sband, ista, priv_sta, changed); } @@ -97,7 +100,7 @@ static inline void rate_control_add_sta_debugfs(struct sta_info *sta) { #ifdef CONFIG_MAC80211_DEBUGFS struct rate_control_ref *ref = sta->rate_ctrl; - if (sta->debugfs.dir && ref->ops->add_sta_debugfs) + if (ref && sta->debugfs.dir && ref->ops->add_sta_debugfs) ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv, sta->debugfs.dir); #endif @@ -107,7 +110,7 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) { #ifdef CONFIG_MAC80211_DEBUGFS struct rate_control_ref *ref = sta->rate_ctrl; - if (ref->ops->remove_sta_debugfs) + if (ref && ref->ops->remove_sta_debugfs) ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv); #endif } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index aa017a56afc..71f370dd24b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -148,8 +148,10 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, static void __sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { - rate_control_free_sta(sta); - rate_control_put(sta->rate_ctrl); + if (sta->rate_ctrl) { + rate_control_free_sta(sta); + rate_control_put(sta->rate_ctrl); + } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Destroyed STA %pM\n", @@ -277,6 +279,23 @@ static void sta_unblock(struct work_struct *wk) ieee80211_sta_ps_deliver_poll_response(sta); } +static int sta_prepare_rate_control(struct ieee80211_local *local, + struct sta_info *sta, gfp_t gfp) +{ + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) + return 0; + + sta->rate_ctrl = rate_control_get(local->rate_ctrl); + sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, + &sta->sta, gfp); + if (!sta->rate_ctrl_priv) { + rate_control_put(sta->rate_ctrl); + return -ENOMEM; + } + + return 0; +} + struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, gfp_t gfp) { @@ -296,11 +315,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->local = local; sta->sdata = sdata; - sta->rate_ctrl = rate_control_get(local->rate_ctrl); - sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, - &sta->sta, gfp); - if (!sta->rate_ctrl_priv) { - rate_control_put(sta->rate_ctrl); + if (sta_prepare_rate_control(local, sta, gfp)) { kfree(sta); return NULL; } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3466e1f7fd1..bd916437e2f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1219,7 +1219,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) CALL_TXH(ieee80211_tx_h_ps_buf); CALL_TXH(ieee80211_tx_h_select_key); CALL_TXH(ieee80211_tx_h_michael_mic_add); - CALL_TXH(ieee80211_tx_h_rate_ctrl); + if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) + CALL_TXH(ieee80211_tx_h_rate_ctrl); CALL_TXH(ieee80211_tx_h_misc); CALL_TXH(ieee80211_tx_h_sequence); CALL_TXH(ieee80211_tx_h_fragment); -- cgit v1.2.3 From 24b6b15f7d07d26330f73057d618089976a08792 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 17 Nov 2009 21:35:38 +0200 Subject: cfg80211: Allow reassociation in associated state cfg80211 rejects all association requests when in associated state. This prevents clean roaming within an ESS since one would first need to disassociate before being able to request reassociation. Accept the reassociation request and let the old association to be dropped when the new one is completed. This fixes nl80211-based roaming with the current snapshot version of wpa_supplicant (that has code for requesting reassociation explicitly withthe previous BSSID attribute). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/wireless/mlme.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 2610b746eff..622af5649b9 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -446,12 +446,23 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct cfg80211_assoc_request req; struct cfg80211_internal_bss *bss; int i, err, slot = -1; + bool was_connected = false; ASSERT_WDEV_LOCK(wdev); memset(&req, 0, sizeof(req)); - if (wdev->current_bss) + if (wdev->current_bss && prev_bssid && + memcmp(wdev->current_bss->pub.bssid, prev_bssid, ETH_ALEN) == 0) { + /* + * Trying to reassociate: Allow this to proceed and let the old + * association to be dropped when the new one is completed. + */ + if (wdev->sme_state == CFG80211_SME_CONNECTED) { + was_connected = true; + wdev->sme_state = CFG80211_SME_CONNECTING; + } + } else if (wdev->current_bss) return -EALREADY; req.ie = ie; @@ -461,8 +472,11 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, req.prev_bssid = prev_bssid; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); - if (!req.bss) + if (!req.bss) { + if (was_connected) + wdev->sme_state = CFG80211_SME_CONNECTED; return -ENOENT; + } bss = bss_from_pub(req.bss); @@ -480,6 +494,8 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, err = rdev->ops->assoc(&rdev->wiphy, dev, &req); out: + if (err && was_connected) + wdev->sme_state = CFG80211_SME_CONNECTED; /* still a reference in wdev->auth_bsses[slot] */ cfg80211_put_bss(req.bss); return err; -- cgit v1.2.3 From 0bc6b1871c111d8f2eb2ac022a705de4cf21f572 Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 18 Nov 2009 11:42:14 +0530 Subject: mac80211: Fix panic in aggregation handling Not assigning the vif pointer causes an oops. This patch fixes it. Signed-off-by: Sujith Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 6ddd11466df..26d42e88808 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -489,6 +489,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, ra_tid = (struct ieee80211_ra_tid *) &skb->cb; memcpy(&ra_tid->ra, ra, ETH_ALEN); ra_tid->tid = tid; + ra_tid->vif = vif; skb->pkt_type = IEEE80211_ADDBA_MSG; skb_queue_tail(&local->skb_queue, skb); @@ -625,6 +626,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, ra_tid = (struct ieee80211_ra_tid *) &skb->cb; memcpy(&ra_tid->ra, ra, ETH_ALEN); ra_tid->tid = tid; + ra_tid->vif = vif; skb->pkt_type = IEEE80211_DELBA_MSG; skb_queue_tail(&local->skb_queue, skb); -- cgit v1.2.3 From 98d3a7ca9232a436c067888936a0133e64ea126a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Nov 2009 13:03:43 +0100 Subject: cfg80211: re-join IBSS when privacy changes When going from/to a WEP protected IBSS, we need to leave this one and join a new one to take care of the changed capability. Cc: Hong Zhang Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.h | 2 ++ net/wireless/ibss.c | 4 ++-- net/wireless/wext-compat.c | 49 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 44 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/wireless/core.h b/net/wireless/core.h index 5aeebb9085f..a9db9e6255b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -273,6 +273,8 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct cfg80211_ibss_params *params, struct cfg80211_cached_keys *connkeys); void cfg80211_clear_ibss(struct net_device *dev, bool nowext); +int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext); int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, struct net_device *dev, bool nowext); void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 39b6d92e282..34dfc93fa71 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -169,8 +169,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) wdev_unlock(wdev); } -static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool nowext) +int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 41abcbdc5fb..29091ac9f98 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -437,6 +437,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, { struct wireless_dev *wdev = dev->ieee80211_ptr; int err, i; + bool rejoin = false; if (!wdev->wext.keys) { wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), @@ -466,8 +467,24 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (remove) { err = 0; - if (wdev->current_bss) + if (wdev->current_bss) { + /* + * If removing the current TX key, we will need to + * join a new IBSS without the privacy bit clear. + */ + if (idx == wdev->wext.default_key && + wdev->iftype == NL80211_IFTYPE_ADHOC) { + __cfg80211_leave_ibss(rdev, wdev->netdev, true); + rejoin = true; + } err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); + } + /* + * Applications using wireless extensions expect to be + * able to delete keys that don't exist, so allow that. + */ + if (err == -ENOENT) + err = 0; if (!err) { if (!addr) { wdev->wext.keys->params[idx].key_len = 0; @@ -478,12 +495,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, else if (idx == wdev->wext.default_mgmt_key) wdev->wext.default_mgmt_key = -1; } - /* - * Applications using wireless extensions expect to be - * able to delete keys that don't exist, so allow that. - */ - if (err == -ENOENT) - return 0; + + if (!err && rejoin) + err = cfg80211_ibss_wext_join(rdev, wdev); return err; } @@ -511,11 +525,25 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || params->cipher == WLAN_CIPHER_SUITE_WEP104) && (tx_key || (!addr && wdev->wext.default_key == -1))) { - if (wdev->current_bss) + if (wdev->current_bss) { + /* + * If we are getting a new TX key from not having + * had one before we need to join a new IBSS with + * the privacy bit set. + */ + if (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->wext.default_key == -1) { + __cfg80211_leave_ibss(rdev, wdev->netdev, true); + rejoin = true; + } err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); - if (!err) + } + if (!err) { wdev->wext.default_key = idx; + if (rejoin) + err = cfg80211_ibss_wext_join(rdev, wdev); + } return err; } @@ -539,10 +567,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, { int err; + /* devlist mutex needed for possible IBSS re-join */ + mutex_lock(&rdev->devlist_mtx); wdev_lock(dev->ieee80211_ptr); err = __cfg80211_set_encryption(rdev, dev, addr, remove, tx_key, idx, params); wdev_unlock(dev->ieee80211_ptr); + mutex_unlock(&rdev->devlist_mtx); return err; } -- cgit v1.2.3 From 875405a7793e9c35fab33819e7e5df7a98b6064c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 18 Nov 2009 16:48:01 +0100 Subject: rfkill: Add constant for RFKILL_TYPE_FM radio devices Signed-off-by: Marcel Holtmann Signed-off-by: Janakiram Sistla Signed-off-by: John W. Linville --- include/linux/rfkill.h | 2 ++ net/rfkill/core.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index a75e9e566ce..97059d08a62 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -36,6 +36,7 @@ * @RFKILL_TYPE_WIMAX: switch is on a WiMAX device. * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device. * @RFKILL_TYPE_GPS: switch is on a GPS device. + * @RFKILL_TYPE_FM: switch is on a FM radio device. * @NUM_RFKILL_TYPES: number of defined rfkill types */ enum rfkill_type { @@ -46,6 +47,7 @@ enum rfkill_type { RFKILL_TYPE_WIMAX, RFKILL_TYPE_WWAN, RFKILL_TYPE_GPS, + RFKILL_TYPE_FM, NUM_RFKILL_TYPES, }; diff --git a/net/rfkill/core.c b/net/rfkill/core.c index ba2efb960c6..09f4e161799 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -592,11 +592,13 @@ static const char *rfkill_get_type_str(enum rfkill_type type) return "wwan"; case RFKILL_TYPE_GPS: return "gps"; + case RFKILL_TYPE_FM: + return "fm"; default: BUG(); } - BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_GPS + 1); + BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_FM + 1); } static ssize_t rfkill_type_show(struct device *dev, -- cgit v1.2.3 From 62ae67be31c2346b6d74653a148ddbd1b9a94424 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Nov 2009 18:42:05 +0100 Subject: mac80211: remove encrypt parameter from ieee80211_tx_skb Since the flags moved into skb->cb, there's no longer a need to have the encrypt bool passed into the function, anyone who requires it set to 0 (false) can just set the flag directly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-rx.c | 2 +- net/mac80211/agg-tx.c | 5 +++-- net/mac80211/ht.c | 2 +- net/mac80211/ibss.c | 3 ++- net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/mesh_hwmp.c | 4 ++-- net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 13 +++++++++---- net/mac80211/rx.c | 2 +- net/mac80211/spectmgmt.c | 2 +- net/mac80211/tx.c | 7 +------ net/mac80211/util.c | 6 ++++-- 12 files changed, 27 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index f3a5c9e0578..7ed5fe66473 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -171,7 +171,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); } void ieee80211_process_addba_request(struct ieee80211_local *local, diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 26d42e88808..b50b2bc3b8c 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -91,7 +91,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.addba_req.start_seq_num = cpu_to_le16(start_seq_num << 4); - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); } void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) @@ -120,7 +120,8 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 bar->control = cpu_to_le16(bar_control); bar->start_seq_num = cpu_to_le16(ssn); - ieee80211_tx_skb(sdata, skb, 0); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 345c8ee5017..15c9d4f94ce 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -134,7 +134,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.delba.params = cpu_to_le16(params); mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); } void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index fbffce90edb..10d13856f86 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -659,7 +659,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", sdata->dev->name, resp->da); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - ieee80211_tx_skb(sdata, skb, 0); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a1bd4b2bc9e..598db7cbeb4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1015,8 +1015,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke struct ieee80211_hdr *hdr, const u8 *tsc, gfp_t gfp); void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); -void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - int encrypt); +void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems); u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index d93019874e4..9aecf0207af 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -187,7 +187,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, memcpy(pos, &target_sn, 4); } - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); return 0; } @@ -250,7 +250,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, pos += 4; memcpy(pos, &target_rcode, 2); - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); return 0; } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index f21329afdae..0f7c6e6a424 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -222,7 +222,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, memcpy(pos, &reason, 2); } - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); return 0; } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2af306f67d7..f399547306c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -426,7 +426,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); } - ieee80211_tx_skb(sdata, skb, 0); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } @@ -467,7 +468,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); else cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); - ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); + if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } void ieee80211_send_pspoll(struct ieee80211_local *local, @@ -498,7 +501,8 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); - ieee80211_tx_skb(sdata, skb, 0); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } void ieee80211_send_nullfunc(struct ieee80211_local *local, @@ -531,7 +535,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); - ieee80211_tx_skb(sdata, skb, 0); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } /* spectrum management related things */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e0cb3357f79..775365f856c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1666,7 +1666,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.sa_query.trans_id, WLAN_SA_QUERY_TR_ID_LEN); - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); } static ieee80211_rx_result debug_noinline diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 68953033403..aa743a895cf 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -65,7 +65,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED; msr_report->u.action.u.measurement.msr_elem.type = request_ie->type; - ieee80211_tx_skb(sdata, skb, 1); + ieee80211_tx_skb(sdata, skb); } void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bd916437e2f..b3c1faeb592 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2281,17 +2281,12 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_get_buffered_bc); -void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - int encrypt) +void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); skb_set_mac_header(skb, 0); skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - if (!encrypt) - info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - /* * The other path calling ieee80211_xmit is from the tasklet, * and while we can handle concurrent transmissions locking diff --git a/net/mac80211/util.c b/net/mac80211/util.c index da86e1592f8..5ae1bf38984 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -872,7 +872,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, WARN_ON(err); } - ieee80211_tx_skb(sdata, skb, 0); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, @@ -974,7 +975,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, local->hw.conf.channel->band)); - ieee80211_tx_skb(sdata, skb, 0); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + ieee80211_tx_skb(sdata, skb); } u32 ieee80211_sta_get_rates(struct ieee80211_local *local, -- cgit v1.2.3 From fe7a5d5c1ad659bf0ec7dc171e122aeefa16ac25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Nov 2009 18:42:47 +0100 Subject: mac80211: move TX status handling It's enough code to have its own file, I think. Especially since I'm going to add to it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Makefile | 2 +- net/mac80211/ieee80211_i.h | 13 ++ net/mac80211/main.c | 336 -------------------------------------------- net/mac80211/status.c | 337 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 351 insertions(+), 337 deletions(-) create mode 100644 net/mac80211/status.c (limited to 'net') diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 9f3cf712932..298cfcc1bf8 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o # mac80211 objects mac80211-y := \ - main.o \ + main.o status.o \ sta_info.o \ wep.o \ wpa.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 598db7cbeb4..74e79935de0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include "key.h" @@ -948,6 +949,18 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); +/* + * radiotap header for status frames + */ +struct ieee80211_tx_status_rtap_hdr { + struct ieee80211_radiotap_header hdr; + u8 rate; + u8 padding_for_rate; + __le16 tx_flags; + u8 data_retries; +} __attribute__ ((packed)); + + /* HT */ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, struct ieee80211_ht_cap *ht_cap_ie, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f4be97c3b74..e843a912849 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -30,26 +29,11 @@ #include "rate.h" #include "mesh.h" #include "wep.h" -#include "wme.h" -#include "aes_ccm.h" #include "led.h" #include "cfg.h" #include "debugfs.h" #include "debugfs_netdev.h" -/* - * For seeing transmitted packets on monitor interfaces - * we have a radiotap header too. - */ -struct ieee80211_tx_status_rtap_hdr { - struct ieee80211_radiotap_header hdr; - u8 rate; - u8 padding_for_rate; - __le16 tx_flags; - u8 data_retries; -} __attribute__ ((packed)); - - void ieee80211_configure_filter(struct ieee80211_local *local) { u64 mc; @@ -253,28 +237,6 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) BSS_CHANGED_ERP_SLOT; } -void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int tmp; - - skb->pkt_type = IEEE80211_TX_STATUS_MSG; - skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? - &local->skb_queue : &local->skb_queue_unreliable, skb); - tmp = skb_queue_len(&local->skb_queue) + - skb_queue_len(&local->skb_queue_unreliable); - while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && - (skb = skb_dequeue(&local->skb_queue_unreliable))) { - dev_kfree_skb_irq(skb); - tmp--; - I802_DEBUG_INC(local->tx_status_drop); - } - tasklet_schedule(&local->tasklet); -} -EXPORT_SYMBOL(ieee80211_tx_status_irqsafe); - static void ieee80211_tasklet_handler(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; @@ -315,304 +277,6 @@ static void ieee80211_tasklet_handler(unsigned long data) } } -static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, - struct sta_info *sta, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - /* - * XXX: This is temporary! - * - * The problem here is that when we get here, the driver will - * quite likely have pretty much overwritten info->control by - * using info->driver_data or info->rate_driver_data. Thus, - * when passing out the frame to the driver again, we would be - * passing completely bogus data since the driver would then - * expect a properly filled info->control. In mac80211 itself - * the same problem occurs, since we need info->control.vif - * internally. - * - * To fix this, we should send the frame through TX processing - * again. However, it's not that simple, since the frame will - * have been software-encrypted (if applicable) already, and - * encrypting it again doesn't do much good. So to properly do - * that, we not only have to skip the actual 'raw' encryption - * (key selection etc. still has to be done!) but also the - * sequence number assignment since that impacts the crypto - * encapsulation, of course. - * - * Hence, for now, fix the bug by just dropping the frame. - */ - goto drop; - - sta->tx_filtered_count++; - - /* - * Clear the TX filter mask for this STA when sending the next - * packet. If the STA went to power save mode, this will happen - * when it wakes up for the next time. - */ - set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); - - /* - * This code races in the following way: - * - * (1) STA sends frame indicating it will go to sleep and does so - * (2) hardware/firmware adds STA to filter list, passes frame up - * (3) hardware/firmware processes TX fifo and suppresses a frame - * (4) we get TX status before having processed the frame and - * knowing that the STA has gone to sleep. - * - * This is actually quite unlikely even when both those events are - * processed from interrupts coming in quickly after one another or - * even at the same time because we queue both TX status events and - * RX frames to be processed by a tasklet and process them in the - * same order that they were received or TX status last. Hence, there - * is no race as long as the frame RX is processed before the next TX - * status, which drivers can ensure, see below. - * - * Note that this can only happen if the hardware or firmware can - * actually add STAs to the filter list, if this is done by the - * driver in response to set_tim() (which will only reduce the race - * this whole filtering tries to solve, not completely solve it) - * this situation cannot happen. - * - * To completely solve this race drivers need to make sure that they - * (a) don't mix the irq-safe/not irq-safe TX status/RX processing - * functions and - * (b) always process RX events before TX status events if ordering - * can be unknown, for example with different interrupt status - * bits. - */ - if (test_sta_flags(sta, WLAN_STA_PS_STA) && - skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - skb_queue_tail(&sta->tx_filtered, skb); - return; - } - - if (!test_sta_flags(sta, WLAN_STA_PS_STA) && - !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { - /* Software retry the packet once */ - info->flags |= IEEE80211_TX_INTFL_RETRIED; - ieee80211_add_pending_skb(local, skb); - return; - } - - drop: -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped TX filtered frame, " - "queue_len=%d PS=%d @%lu\n", - wiphy_name(local->hw.wiphy), - skb_queue_len(&sta->tx_filtered), - !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); -#endif - dev_kfree_skb(skb); -} - -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct sk_buff *skb2; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u16 frag, type; - __le16 fc; - struct ieee80211_supported_band *sband; - struct ieee80211_tx_status_rtap_hdr *rthdr; - struct ieee80211_sub_if_data *sdata; - struct net_device *prev_dev = NULL; - struct sta_info *sta; - int retry_count = -1, i; - - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - /* the HW cannot have attempted that rate */ - if (i >= hw->max_rates) { - info->status.rates[i].idx = -1; - info->status.rates[i].count = 0; - } - - retry_count += info->status.rates[i].count; - } - if (retry_count < 0) - retry_count = 0; - - rcu_read_lock(); - - sband = local->hw.wiphy->bands[info->band]; - - sta = sta_info_get(local, hdr->addr1); - - if (sta) { - if (!(info->flags & IEEE80211_TX_STAT_ACK) && - test_sta_flags(sta, WLAN_STA_PS_STA)) { - /* - * The STA is in power save mode, so assume - * that this TX packet failed because of that. - */ - ieee80211_handle_filtered_frame(local, sta, skb); - rcu_read_unlock(); - return; - } - - fc = hdr->frame_control; - - if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && - (ieee80211_is_data_qos(fc))) { - u16 tid, ssn; - u8 *qc; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) - & IEEE80211_SCTL_SEQ); - ieee80211_send_bar(sta->sdata, hdr->addr1, - tid, ssn); - } - - if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - ieee80211_handle_filtered_frame(local, sta, skb); - rcu_read_unlock(); - return; - } else { - if (!(info->flags & IEEE80211_TX_STAT_ACK)) - sta->tx_retry_failed++; - sta->tx_retry_count += retry_count; - } - - rate_control_tx_status(local, sband, sta, skb); - if (ieee80211_vif_is_mesh(&sta->sdata->vif)) - ieee80211s_update_metric(local, sta, skb); - } - - rcu_read_unlock(); - - ieee80211_led_tx(local, 0); - - /* SNMP counters - * Fragments are passed to low-level drivers as separate skbs, so these - * are actually fragments, not frames. Update frame counters only for - * the first fragment of the frame. */ - - frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; - type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - - if (info->flags & IEEE80211_TX_STAT_ACK) { - if (frag == 0) { - local->dot11TransmittedFrameCount++; - if (is_multicast_ether_addr(hdr->addr1)) - local->dot11MulticastTransmittedFrameCount++; - if (retry_count > 0) - local->dot11RetryCount++; - if (retry_count > 1) - local->dot11MultipleRetryCount++; - } - - /* This counter shall be incremented for an acknowledged MPDU - * with an individual address in the address 1 field or an MPDU - * with a multicast address in the address 1 field of type Data - * or Management. */ - if (!is_multicast_ether_addr(hdr->addr1) || - type == IEEE80211_FTYPE_DATA || - type == IEEE80211_FTYPE_MGMT) - local->dot11TransmittedFragmentCount++; - } else { - if (frag == 0) - local->dot11FailedCount++; - } - - /* this was a transmitted frame, but now we want to reuse it */ - skb_orphan(skb); - - /* - * This is a bit racy but we can avoid a lot of work - * with this test... - */ - if (!local->monitors && !local->cooked_mntrs) { - dev_kfree_skb(skb); - return; - } - - /* send frame to monitor interfaces now */ - - if (skb_headroom(skb) < sizeof(*rthdr)) { - printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); - dev_kfree_skb(skb); - return; - } - - rthdr = (struct ieee80211_tx_status_rtap_hdr *) - skb_push(skb, sizeof(*rthdr)); - - memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | - (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | - (1 << IEEE80211_RADIOTAP_RATE)); - - if (!(info->flags & IEEE80211_TX_STAT_ACK) && - !is_multicast_ether_addr(hdr->addr1)) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); - - /* - * XXX: Once radiotap gets the bitmap reset thing the vendor - * extensions proposal contains, we can actually report - * the whole set of tries we did. - */ - if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || - (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); - if (info->status.rates[0].idx >= 0 && - !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) - rthdr->rate = sband->bitrates[ - info->status.rates[0].idx].bitrate / 5; - - /* for now report the total retry_count */ - rthdr->data_retries = retry_count; - - /* XXX: is this sufficient for BPF? */ - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { - if (!netif_running(sdata->dev)) - continue; - - if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && - !(info->flags & IEEE80211_TX_CTL_INJECTED) && - (type == IEEE80211_FTYPE_DATA)) - continue; - - if (prev_dev) { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) { - skb2->dev = prev_dev; - netif_rx(skb2); - } - } - - prev_dev = sdata->dev; - } - } - if (prev_dev) { - skb->dev = prev_dev; - netif_rx(skb); - skb = NULL; - } - rcu_read_unlock(); - dev_kfree_skb(skb); -} -EXPORT_SYMBOL(ieee80211_tx_status); - static void ieee80211_restart_work(struct work_struct *work) { struct ieee80211_local *local = diff --git a/net/mac80211/status.c b/net/mac80211/status.c new file mode 100644 index 00000000000..9f91fd8e6ef --- /dev/null +++ b/net/mac80211/status.c @@ -0,0 +1,337 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2008-2009 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include "ieee80211_i.h" +#include "rate.h" +#include "mesh.h" +#include "led.h" + + +void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int tmp; + + skb->pkt_type = IEEE80211_TX_STATUS_MSG; + skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? + &local->skb_queue : &local->skb_queue_unreliable, skb); + tmp = skb_queue_len(&local->skb_queue) + + skb_queue_len(&local->skb_queue_unreliable); + while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && + (skb = skb_dequeue(&local->skb_queue_unreliable))) { + dev_kfree_skb_irq(skb); + tmp--; + I802_DEBUG_INC(local->tx_status_drop); + } + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_tx_status_irqsafe); + +static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, + struct sta_info *sta, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + /* + * XXX: This is temporary! + * + * The problem here is that when we get here, the driver will + * quite likely have pretty much overwritten info->control by + * using info->driver_data or info->rate_driver_data. Thus, + * when passing out the frame to the driver again, we would be + * passing completely bogus data since the driver would then + * expect a properly filled info->control. In mac80211 itself + * the same problem occurs, since we need info->control.vif + * internally. + * + * To fix this, we should send the frame through TX processing + * again. However, it's not that simple, since the frame will + * have been software-encrypted (if applicable) already, and + * encrypting it again doesn't do much good. So to properly do + * that, we not only have to skip the actual 'raw' encryption + * (key selection etc. still has to be done!) but also the + * sequence number assignment since that impacts the crypto + * encapsulation, of course. + * + * Hence, for now, fix the bug by just dropping the frame. + */ + goto drop; + + sta->tx_filtered_count++; + + /* + * Clear the TX filter mask for this STA when sending the next + * packet. If the STA went to power save mode, this will happen + * when it wakes up for the next time. + */ + set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT); + + /* + * This code races in the following way: + * + * (1) STA sends frame indicating it will go to sleep and does so + * (2) hardware/firmware adds STA to filter list, passes frame up + * (3) hardware/firmware processes TX fifo and suppresses a frame + * (4) we get TX status before having processed the frame and + * knowing that the STA has gone to sleep. + * + * This is actually quite unlikely even when both those events are + * processed from interrupts coming in quickly after one another or + * even at the same time because we queue both TX status events and + * RX frames to be processed by a tasklet and process them in the + * same order that they were received or TX status last. Hence, there + * is no race as long as the frame RX is processed before the next TX + * status, which drivers can ensure, see below. + * + * Note that this can only happen if the hardware or firmware can + * actually add STAs to the filter list, if this is done by the + * driver in response to set_tim() (which will only reduce the race + * this whole filtering tries to solve, not completely solve it) + * this situation cannot happen. + * + * To completely solve this race drivers need to make sure that they + * (a) don't mix the irq-safe/not irq-safe TX status/RX processing + * functions and + * (b) always process RX events before TX status events if ordering + * can be unknown, for example with different interrupt status + * bits. + */ + if (test_sta_flags(sta, WLAN_STA_PS_STA) && + skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { + skb_queue_tail(&sta->tx_filtered, skb); + return; + } + + if (!test_sta_flags(sta, WLAN_STA_PS_STA) && + !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { + /* Software retry the packet once */ + info->flags |= IEEE80211_TX_INTFL_RETRIED; + ieee80211_add_pending_skb(local, skb); + return; + } + + drop: +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped TX filtered frame, " + "queue_len=%d PS=%d @%lu\n", + wiphy_name(local->hw.wiphy), + skb_queue_len(&sta->tx_filtered), + !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); +#endif + dev_kfree_skb(skb); +} + +void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct sk_buff *skb2; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u16 frag, type; + __le16 fc; + struct ieee80211_supported_band *sband; + struct ieee80211_tx_status_rtap_hdr *rthdr; + struct ieee80211_sub_if_data *sdata; + struct net_device *prev_dev = NULL; + struct sta_info *sta; + int retry_count = -1, i; + + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + /* the HW cannot have attempted that rate */ + if (i >= hw->max_rates) { + info->status.rates[i].idx = -1; + info->status.rates[i].count = 0; + } + + retry_count += info->status.rates[i].count; + } + if (retry_count < 0) + retry_count = 0; + + rcu_read_lock(); + + sband = local->hw.wiphy->bands[info->band]; + + sta = sta_info_get(local, hdr->addr1); + + if (sta) { + if (!(info->flags & IEEE80211_TX_STAT_ACK) && + test_sta_flags(sta, WLAN_STA_PS_STA)) { + /* + * The STA is in power save mode, so assume + * that this TX packet failed because of that. + */ + ieee80211_handle_filtered_frame(local, sta, skb); + rcu_read_unlock(); + return; + } + + fc = hdr->frame_control; + + if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && + (ieee80211_is_data_qos(fc))) { + u16 tid, ssn; + u8 *qc; + + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10) + & IEEE80211_SCTL_SEQ); + ieee80211_send_bar(sta->sdata, hdr->addr1, + tid, ssn); + } + + if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + ieee80211_handle_filtered_frame(local, sta, skb); + rcu_read_unlock(); + return; + } else { + if (!(info->flags & IEEE80211_TX_STAT_ACK)) + sta->tx_retry_failed++; + sta->tx_retry_count += retry_count; + } + + rate_control_tx_status(local, sband, sta, skb); + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + ieee80211s_update_metric(local, sta, skb); + } + + rcu_read_unlock(); + + ieee80211_led_tx(local, 0); + + /* SNMP counters + * Fragments are passed to low-level drivers as separate skbs, so these + * are actually fragments, not frames. Update frame counters only for + * the first fragment of the frame. */ + + frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; + + if (info->flags & IEEE80211_TX_STAT_ACK) { + if (frag == 0) { + local->dot11TransmittedFrameCount++; + if (is_multicast_ether_addr(hdr->addr1)) + local->dot11MulticastTransmittedFrameCount++; + if (retry_count > 0) + local->dot11RetryCount++; + if (retry_count > 1) + local->dot11MultipleRetryCount++; + } + + /* This counter shall be incremented for an acknowledged MPDU + * with an individual address in the address 1 field or an MPDU + * with a multicast address in the address 1 field of type Data + * or Management. */ + if (!is_multicast_ether_addr(hdr->addr1) || + type == IEEE80211_FTYPE_DATA || + type == IEEE80211_FTYPE_MGMT) + local->dot11TransmittedFragmentCount++; + } else { + if (frag == 0) + local->dot11FailedCount++; + } + + /* this was a transmitted frame, but now we want to reuse it */ + skb_orphan(skb); + + /* + * This is a bit racy but we can avoid a lot of work + * with this test... + */ + if (!local->monitors && !local->cooked_mntrs) { + dev_kfree_skb(skb); + return; + } + + /* send frame to monitor interfaces now */ + + if (skb_headroom(skb) < sizeof(*rthdr)) { + printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); + dev_kfree_skb(skb); + return; + } + + rthdr = (struct ieee80211_tx_status_rtap_hdr *) + skb_push(skb, sizeof(*rthdr)); + + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | + (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | + (1 << IEEE80211_RADIOTAP_RATE)); + + if (!(info->flags & IEEE80211_TX_STAT_ACK) && + !is_multicast_ether_addr(hdr->addr1)) + rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); + + /* + * XXX: Once radiotap gets the bitmap reset thing the vendor + * extensions proposal contains, we can actually report + * the whole set of tries we did. + */ + if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) + rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); + else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); + if (info->status.rates[0].idx >= 0 && + !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) + rthdr->rate = sband->bitrates[ + info->status.rates[0].idx].bitrate / 5; + + /* for now report the total retry_count */ + rthdr->data_retries = retry_count; + + /* XXX: is this sufficient for BPF? */ + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { + if (!netif_running(sdata->dev)) + continue; + + if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && + !(info->flags & IEEE80211_TX_CTL_INJECTED) && + (type == IEEE80211_FTYPE_DATA)) + continue; + + if (prev_dev) { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; + } + } + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } + rcu_read_unlock(); + dev_kfree_skb(skb); +} +EXPORT_SYMBOL(ieee80211_tx_status); -- cgit v1.2.3 From 136cfa28615ccce0f9374811480e0b81c4191ea5 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Wed, 18 Nov 2009 18:40:00 +0000 Subject: mac80211: use a structure to hold the mesh config information element Signed-off-by: Rui Paulo Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 16 +++++++++++++++- net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/mesh.c | 23 ++++++++--------------- net/mac80211/util.c | 4 ++-- net/wireless/scan.c | 9 +++++---- 5 files changed, 31 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 49b1abd2fe9..afa8e0ac27a 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -115,7 +115,6 @@ #define IEEE80211_MAX_SSID_LEN 32 #define IEEE80211_MAX_MESH_ID_LEN 32 -#define IEEE80211_MESH_CONFIG_LEN 7 #define IEEE80211_QOS_CTL_LEN 2 #define IEEE80211_QOS_CTL_TID_MASK 0x000F @@ -554,6 +553,21 @@ struct ieee80211_tim_ie { u8 virtual_map[1]; } __attribute__ ((packed)); +/** + * struct ieee80211_meshconf_ie + * + * This structure refers to "Mesh Configuration information element" + */ +struct ieee80211_meshconf_ie { + u8 meshconf_psel; + u8 meshconf_pmetric; + u8 meshconf_congest; + u8 meshconf_synch; + u8 meshconf_auth; + u8 meshconf_form; + u8 meshconf_cap; +} __attribute__ ((packed)); + /** * struct ieee80211_rann_ie * diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 74e79935de0..87d27f450a0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -798,7 +798,7 @@ struct ieee802_11_elems { u8 *wmm_param; struct ieee80211_ht_cap *ht_cap_elem; struct ieee80211_ht_info *ht_info_elem; - u8 *mesh_config; + struct ieee80211_meshconf_ie *mesh_config; u8 *mesh_id; u8 *peer_link; u8 *preq; @@ -826,7 +826,6 @@ struct ieee802_11_elems { u8 ext_supp_rates_len; u8 wmm_info_len; u8 wmm_param_len; - u8 mesh_config_len; u8 mesh_id_len; u8 peer_link_len; u8 preq_len; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 3a0683ba357..51adb111521 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -16,12 +16,6 @@ #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) #define IEEE80211_MESH_RANN_INTERVAL (1 * HZ) -#define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */ -#define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */ -#define MESHCONF_CC_OFFSET 2 /* Congestion Control Mode */ -#define MESHCONF_SP_OFFSET 3 /* Synchronization Protocol */ -#define MESHCONF_AUTH_OFFSET 4 /* Authentication Protocol */ -#define MESHCONF_CAPAB_OFFSET 6 #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 #define MESHCONF_CAPAB_FORWARDING 0x08 @@ -87,12 +81,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ if (ifmsh->mesh_id_len == ie->mesh_id_len && memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && - (ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&& - (ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&& - (ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&& - (ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&& - (ifmsh->mesh_auth_id == *(ie->mesh_config + - MESHCONF_AUTH_OFFSET))) + (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) && + (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) && + (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) && + (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) && + (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)) return true; return false; @@ -105,7 +98,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) { - return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) & + return (ie->mesh_config->meshconf_cap & MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; } @@ -262,9 +255,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) if (sdata->u.mesh.mesh_id_len) memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len); - pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); + pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie)); *pos++ = WLAN_EID_MESH_CONFIG; - *pos++ = IEEE80211_MESH_CONFIG_LEN; + *pos++ = sizeof(struct ieee80211_meshconf_ie); /* Active path selection protocol ID */ *pos++ = sdata->u.mesh.mesh_pp_id; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5ae1bf38984..2fb0432ac83 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -666,8 +666,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, elems->mesh_id_len = elen; break; case WLAN_EID_MESH_CONFIG: - elems->mesh_config = pos; - elems->mesh_config_len = elen; + if (elen >= sizeof(struct ieee80211_meshconf_ie)) + elems->mesh_config = (void *)pos; break; case WLAN_EID_PEER_LINK: elems->peer_link = pos; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e2d344ff674..d03447d68cd 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -217,7 +217,7 @@ static bool is_mesh(struct cfg80211_bss *a, a->len_information_elements); if (!ie) return false; - if (ie[1] != IEEE80211_MESH_CONFIG_LEN) + if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) return false; /* @@ -225,7 +225,8 @@ static bool is_mesh(struct cfg80211_bss *a, * comparing since that may differ between stations taking * part in the same mesh. */ - return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0; + return memcmp(ie + 2, meshcfg, + sizeof(struct ieee80211_meshconf_ie) - 2) == 0; } static int cmp_bss(struct cfg80211_bss *a, @@ -399,7 +400,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, res->pub.information_elements, res->pub.len_information_elements); if (!meshid || !meshcfg || - meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) { + meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) { /* bogus mesh */ kref_put(&res->ref, bss_release); return NULL; @@ -865,7 +866,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, break; case WLAN_EID_MESH_CONFIG: ismesh = true; - if (ie[1] != IEEE80211_MESH_CONFIG_LEN) + if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) break; buf = kmalloc(50, GFP_ATOMIC); if (!buf) -- cgit v1.2.3 From 76aa5e704c80fb7ca8bd3d05593d9a28298c92cd Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Wed, 18 Nov 2009 18:22:59 +0000 Subject: mac80211: update cfg80211 scan result code for the updated mesh conf IE Signed-off-by: Rui Paulo Signed-off-by: John W. Linville --- net/wireless/scan.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/wireless/scan.c b/net/wireless/scan.c index d03447d68cd..227d57b8dc4 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -874,35 +874,40 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, cfg = ie + 2; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - sprintf(buf, "Mesh network (version %d)", cfg[0]); + sprintf(buf, "Mesh Network Path Selection Protocol ID: " + "0x%02X", cfg[0]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); - sprintf(buf, "Path Selection Protocol ID: " - "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], - cfg[4]); + sprintf(buf, "Path Selection Metric ID: 0x%02X", + cfg[1]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); - sprintf(buf, "Path Selection Metric ID: " - "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], - cfg[8]); + sprintf(buf, "Congestion Control Mode ID: 0x%02X", + cfg[2]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); - sprintf(buf, "Congestion Control Mode ID: " - "0x%02X%02X%02X%02X", cfg[9], cfg[10], - cfg[11], cfg[12]); + sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); - sprintf(buf, "Channel Precedence: " - "0x%02X%02X%02X%02X", cfg[13], cfg[14], - cfg[15], cfg[16]); + sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Formation Info: 0x%02X", cfg[5]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info, current_ev, + end_buf, + &iwe, buf); + sprintf(buf, "Capabilities: 0x%02X", cfg[6]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, -- cgit v1.2.3 From 2939e275994977b6c9eb7fd082b7b0caa35b96b0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Nov 2009 23:24:41 -0800 Subject: netsched: Allow var_sk_bound_if meta to work on all namespaces This fix can probably wait 2.6.33, or should use another patch if needed in 2.6.32 (no get_dev_by_index_rcu() before 2.6.33) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/em_meta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 8e8d836f00c..24dce8b648a 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -310,7 +310,8 @@ META_COLLECTOR(var_sk_bound_if) struct net_device *dev; rcu_read_lock(); - dev = dev_get_by_index_rcu(&init_net, skb->sk->sk_bound_dev_if); + dev = dev_get_by_index_rcu(sock_net(skb->sk), + skb->sk->sk_bound_dev_if); *err = var_dev(dev, dst); rcu_read_unlock(); } -- cgit v1.2.3 From 386e50cc7d82b3799ea6f53267f04f123ae05afe Mon Sep 17 00:00:00 2001 From: Andrew Hendry Date: Wed, 18 Nov 2009 23:30:41 -0800 Subject: X25: Enable setting of cause and diagnostic fields Adds SIOCX25SCAUSEDIAG, allowing X.25 programs to set the cause and diagnostic fields. Normally used to indicate status upon closing connections. Signed-off-by: Andrew Hendry Signed-off-by: David S. Miller --- include/linux/x25.h | 1 + net/x25/af_x25.c | 12 ++++++++++++ net/x25/x25_subr.c | 6 ++++++ 3 files changed, 19 insertions(+) (limited to 'net') diff --git a/include/linux/x25.h b/include/linux/x25.h index d035e4e87d0..6450a7f1207 100644 --- a/include/linux/x25.h +++ b/include/linux/x25.h @@ -25,6 +25,7 @@ #define SIOCX25SENDCALLACCPT (SIOCPROTOPRIVATE + 9) #define SIOCX25GDTEFACILITIES (SIOCPROTOPRIVATE + 10) #define SIOCX25SDTEFACILITIES (SIOCPROTOPRIVATE + 11) +#define SIOCX25SCAUSEDIAG (SIOCPROTOPRIVATE + 12) /* * Values for {get,set}sockopt. diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 39ce03e07d1..ac7dba46fa3 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1471,6 +1471,17 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; } + case SIOCX25SCAUSEDIAG: { + struct x25_causediag causediag; + rc = -EFAULT; + if (copy_from_user(&causediag, argp, sizeof(causediag))) + break; + x25->causediag = causediag; + rc = 0; + break; + + } + case SIOCX25SCUDMATCHLEN: { struct x25_subaddr sub_addr; rc = -EINVAL; @@ -1639,6 +1650,7 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, case SIOCX25GCALLUSERDATA: case SIOCX25SCALLUSERDATA: case SIOCX25GCAUSEDIAG: + case SIOCX25SCAUSEDIAG: case SIOCX25SCUDMATCHLEN: case SIOCX25CALLACCPTAPPRV: case SIOCX25SENDCALLACCPT: diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c index 511a5986af3..352b32d216f 100644 --- a/net/x25/x25_subr.c +++ b/net/x25/x25_subr.c @@ -225,6 +225,12 @@ void x25_write_internal(struct sock *sk, int frametype) break; case X25_CLEAR_REQUEST: + dptr = skb_put(skb, 3); + *dptr++ = frametype; + *dptr++ = x25->causediag.cause; + *dptr++ = x25->causediag.diagnostic; + break; + case X25_RESET_REQUEST: dptr = skb_put(skb, 3); *dptr++ = frametype; -- cgit v1.2.3 From 5be83de54c16944dea9c16c6a5a53c1fa75ed304 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 00:56:28 +0100 Subject: cfg80211: convert bools into flags We've accumulated a number of options for wiphys which make more sense as flags as we keep adding more. Convert the existing ones. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 5 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +-- drivers/net/wireless/mac80211_hwsim.c | 18 ++++----- drivers/net/wireless/p54/main.c | 2 +- include/net/cfg80211.h | 62 ++++++++++++++++------------- net/mac80211/main.c | 2 +- net/wireless/Kconfig | 6 --- net/wireless/core.c | 13 ++++-- net/wireless/nl80211.c | 2 +- net/wireless/reg.c | 13 +++--- 11 files changed, 70 insertions(+), 67 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 077bcc142cd..039ac490465 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; - wiphy->strict_regulatory = true; + wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; if (ath_is_world_regd(reg)) { /* @@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, * saved on the wiphy orig_* parameters */ regd = ath_world_regdomain(reg); - wiphy->custom_regulatory = true; - wiphy->strict_regulatory = false; + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; } else { /* * This gets applied in the case of the absense of CRDA, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b80cd0bc584..e8f405a01e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2400,16 +2400,14 @@ static int iwl_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->custom_regulatory = true; - - /* Firmware does not support this */ - hw->wiphy->disable_beacon_hints = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + WIPHY_FLAG_DISABLE_BEACON_HINTS; /* * For now, disable PS by default because it affects * RX performance significantly. */ - hw->wiphy->ps_default = false; + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 31f3c42b835..5b7e80e5bab 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3904,10 +3904,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->custom_regulatory = true; - - /* Firmware does not support this */ - hw->wiphy->disable_beacon_hints = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + WIPHY_FLAG_DISABLE_BEACON_HINTS; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; /* we create the 802.11 header and a zero-length SSID element */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index fc4ec48eda1..88e41176e7f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1146,46 +1146,46 @@ static int __init init_mac80211_hwsim(void) break; case HWSIM_REGTEST_WORLD_ROAM: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } break; case HWSIM_REGTEST_CUSTOM_WORLD: - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); break; case HWSIM_REGTEST_CUSTOM_WORLD_2: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } break; case HWSIM_REGTEST_STRICT_ALL: - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; case HWSIM_REGTEST_STRICT_FOLLOW: case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: if (i == 0) - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; case HWSIM_REGTEST_ALL: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } else if (i == 4) - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; default: break; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 4d486bf9f72..18012dbfb45 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -579,7 +579,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) * For now, disable PS by default because it affects * link stability significantly. */ - dev->wiphy->ps_default = false; + dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 21710fc17ea..eca36abca8f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1108,27 +1108,45 @@ struct cfg80211_ops { */ /** - * struct wiphy - wireless hardware description - * @idx: the wiphy index assigned to this item - * @class_dev: the class device representing /sys/class/ieee80211/ - * @custom_regulatory: tells us the driver for this device + * enum wiphy_flags - wiphy capability flags + * + * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device * has its own custom regulatory domain and cannot identify the * ISO / IEC 3166 alpha2 it belongs to. When this is enabled * we will disregard the first regulatory hint (when the * initiator is %REGDOM_SET_BY_CORE). - * @strict_regulatory: tells us the driver for this device will ignore - * regulatory domain settings until it gets its own regulatory domain - * via its regulatory_hint(). After its gets its own regulatory domain - * it will only allow further regulatory domain settings to further - * enhance compliance. For example if channel 13 and 14 are disabled - * by this regulatory domain no user regulatory domain can enable these - * channels at a later time. This can be used for devices which do not - * have calibration information gauranteed for frequencies or settings - * outside of its regulatory domain. - * @disable_beacon_hints: enable this if your driver needs to ensure that - * passive scan flags and beaconing flags may not be lifted by cfg80211 - * due to regulatory beacon hints. For more information on beacon + * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will + * ignore regulatory domain settings until it gets its own regulatory + * domain via its regulatory_hint(). After its gets its own regulatory + * domain it will only allow further regulatory domain settings to + * further enhance compliance. For example if channel 13 and 14 are + * disabled by this regulatory domain no user regulatory domain can + * enable these channels at a later time. This can be used for devices + * which do not have calibration information gauranteed for frequencies + * or settings outside of its regulatory domain. + * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure + * that passive scan flags and beaconing flags may not be lifted by + * cfg80211 due to regulatory beacon hints. For more information on beacon * hints read the documenation for regulatory_hint_found_beacon() + * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this + * wiphy at all + * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled + * by default -- this flag will be set depending on the kernel's default + * on wiphy_new(), but can be changed by the driver if it has a good + * reason to override the default + */ +enum wiphy_flags { + WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), + WIPHY_FLAG_STRICT_REGULATORY = BIT(1), + WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), + WIPHY_FLAG_NETNS_OK = BIT(3), + WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), +}; + +/** + * struct wiphy - wireless hardware description + * @idx: the wiphy index assigned to this item + * @class_dev: the class device representing /sys/class/ieee80211/ * @reg_notifier: the driver's regulatory notification callback * @regd: the driver's regulatory domain, if one was requested via * the regulatory_hint() API. This can be used by the driver @@ -1143,11 +1161,6 @@ struct cfg80211_ops { * -1 = fragmentation disabled, only odd values >= 256 used * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled * @net: the network namespace this wiphy currently lives in - * @netnsok: if set to false, do not allow changing the netns of this - * wiphy at all - * @ps_default: default for powersave, will be set depending on the - * kernel's default on wiphy_new(), but can be changed by the - * driver if it has a good reason to override the default */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -1158,12 +1171,7 @@ struct wiphy { /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ u16 interface_modes; - bool custom_regulatory; - bool strict_regulatory; - bool disable_beacon_hints; - - bool netnsok; - bool ps_default; + u32 flags; enum cfg80211_signal_type signal_type; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e843a912849..8084b622e97 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -328,7 +328,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; - wiphy->netnsok = true; + wiphy->flags |= WIPHY_FLAG_NETNS_OK; wiphy->privid = mac80211_wiphy_privid; /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 614bdcec1c8..90e93a5701a 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -74,12 +74,6 @@ 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 diff --git a/net/wireless/core.c b/net/wireless/core.c index 02835172b22..e2cc6e7522d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -230,7 +230,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev; int err = 0; - if (!rdev->wiphy.netnsok) + if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) return -EOPNOTSUPP; list_for_each_entry(wdev, &rdev->netdev_list, list) { @@ -367,7 +367,9 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; - rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; +#ifdef CONFIG_CFG80211_DEFAULT_PS + rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif wiphy_net_set(&rdev->wiphy, &init_net); @@ -482,7 +484,7 @@ int wiphy_register(struct wiphy *wiphy) if (IS_ERR(rdev->wiphy.debugfsdir)) rdev->wiphy.debugfsdir = NULL; - if (wiphy->custom_regulatory) { + if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { struct regulatory_request request; request.wiphy_idx = get_wiphy_idx(wiphy); @@ -680,7 +682,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; - wdev->wext.ps = wdev->wiphy->ps_default; + if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) + wdev->wext.ps = true; + else + wdev->wext.ps = false; wdev->wext.ps_timeout = 100; if (rdev->ops->set_power_mgmt) if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37264d56bac..6634188f945 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -561,7 +561,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); CMD(join_ibss, JOIN_IBSS); - if (dev->wiphy.netnsok) { + if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f256dfffbf4..1f33017737f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1008,7 +1008,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && - request_wiphy->strict_regulatory) { + request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { /* * This gaurantees the driver's requested regulatory domain * will always be used as a base for further regulatory @@ -1051,13 +1051,13 @@ static bool ignore_reg_update(struct wiphy *wiphy, if (!last_request) return true; if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->custom_regulatory) + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; /* * wiphy->regd will be set once the device has its own * desired regulatory domain set */ - if (wiphy->strict_regulatory && !wiphy->regd && + if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && !is_world_regdom(last_request->alpha2)) return true; return false; @@ -1093,7 +1093,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, chan->beacon_found = true; - if (wiphy->disable_beacon_hints) + if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) return; chan_before.center_freq = chan->center_freq; @@ -1164,7 +1164,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) return true; if (last_request && last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->custom_regulatory) + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; return false; } @@ -1591,7 +1591,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) r = __regulatory_hint(wiphy, reg_request); /* This is required so that the orig_* parameters are saved */ - if (r == -EALREADY && wiphy && wiphy->strict_regulatory) + if (r == -EALREADY && wiphy && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) wiphy_update_regulatory(wiphy, reg_request->initiator); out: mutex_unlock(®_mutex); -- cgit v1.2.3 From 9bc383de37090ba7ca3ff32a12c9d809dc5867f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 11:55:19 +0100 Subject: cfg80211: introduce capability for 4addr mode It's very likely that not many devices will support four-address mode in station or AP mode so introduce capability bits for both modes, set them in mac80211 and check them when userspace tries to use the mode. Also, keep track of 4addr in cfg80211 (wireless_dev) and not in mac80211 any more. mac80211 can also be improved for the VLAN case by not looking at the 4addr flag but maintaining the station pointer for it correctly. However, keep track of use_4addr for station mode in mac80211 to avoid all the derefs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 11 +++++++++++ net/mac80211/cfg.c | 21 ++++++++------------- net/mac80211/ieee80211_i.h | 4 ++-- net/mac80211/iface.c | 12 ++++++++---- net/mac80211/main.c | 4 +++- net/mac80211/rx.c | 14 +++++++++----- net/mac80211/tx.c | 7 +++---- net/wireless/nl80211.c | 34 +++++++++++++++++++++++++++++++++- net/wireless/util.c | 5 +++++ 9 files changed, 82 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index eca36abca8f..d1e05aeb0c0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1134,6 +1134,9 @@ struct cfg80211_ops { * by default -- this flag will be set depending on the kernel's default * on wiphy_new(), but can be changed by the driver if it has a good * reason to override the default + * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station + * on a VLAN interface) + * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station */ enum wiphy_flags { WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), @@ -1141,6 +1144,8 @@ enum wiphy_flags { WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), WIPHY_FLAG_NETNS_OK = BIT(3), WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), + WIPHY_FLAG_4ADDR_AP = BIT(5), + WIPHY_FLAG_4ADDR_STATION = BIT(6), }; /** @@ -1366,6 +1371,10 @@ struct cfg80211_cached_keys; * @ssid_len: (private) Used by the internal configuration code * @wext: (private) Used by the internal wireless extensions compat code * @wext_bssid: (private) Used by the internal wireless extensions compat code + * @use_4addr: indicates 4addr mode is used on this interface, must be + * set by driver (if supported) on add_interface BEFORE registering the + * netdev and may otherwise be used by driver read-only, will be update + * by cfg80211 on change_interface */ struct wireless_dev { struct wiphy *wiphy; @@ -1379,6 +1388,8 @@ struct wireless_dev { struct work_struct cleanup_work; + bool use_4addr; + /* currently used for IBSS and SME - might be rearranged later */ u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7d591816ed1..c484a882140 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl80211_iftype type, if (!nl80211_type_check(type)) return false; - if (params->use_4addr > 0) { - switch(type) { - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_STATION: - break; - default: - return false; - } - } return true; } @@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy, params->mesh_id_len, params->mesh_id); - if (params->use_4addr >= 0) - sdata->use_4addr = !!params->use_4addr; - if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) return 0; + if (type == NL80211_IFTYPE_AP_VLAN && + params && params->use_4addr == 0) + rcu_assign_pointer(sdata->u.vlan.sta, NULL); + else if (type == NL80211_IFTYPE_STATION && + params && params->use_4addr >= 0) + sdata->u.mgd.use_4addr = params->use_4addr; + sdata->u.mntr_flags = *flags; return 0; } @@ -827,7 +822,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, return -EINVAL; } - if (vlansdata->use_4addr) { + if (params->vlan->ieee80211_ptr->use_4addr) { if (vlansdata->u.vlan.sta) return -EBUSY; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 87d27f450a0..f13d76c9b57 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -312,6 +312,8 @@ struct ieee80211_if_managed { } mfp; /* management frame protection */ int wmm_last_param_set; + + u8 use_4addr; }; enum ieee80211_ibss_request { @@ -459,8 +461,6 @@ struct ieee80211_sub_if_data { int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ int max_ratectrl_rateidx; /* max TX rateidx for rate control */ - bool use_4addr; /* use 4-address frames */ - union { struct ieee80211_if_ap ap; struct ieee80211_if_wds wds; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1f02b0610e8..1bf12a26b45 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, ieee80211_mandatory_rates(sdata->local, sdata->local->hw.conf.channel->band); sdata->drop_unencrypted = 0; - sdata->use_4addr = 0; + if (type == NL80211_IFTYPE_STATION) + sdata->u.mgd.use_4addr = false; return 0; } @@ -810,6 +811,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); + if (params) { + ndev->ieee80211_ptr->use_4addr = params->use_4addr; + if (type == NL80211_IFTYPE_STATION) + sdata->u.mgd.use_4addr = params->use_4addr; + } + ret = register_netdevice(ndev); if (ret) goto fail; @@ -820,9 +827,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, params->mesh_id_len, params->mesh_id); - if (params && params->use_4addr >= 0) - sdata->use_4addr = !!params->use_4addr; - mutex_lock(&local->iflist_mtx); list_add_tail_rcu(&sdata->list, &local->interfaces); mutex_unlock(&local->iflist_mtx); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8084b622e97..dd8ec8d5e8b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -328,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; - wiphy->flags |= WIPHY_FLAG_NETNS_OK; + wiphy->flags |= WIPHY_FLAG_NETNS_OK | + WIPHY_FLAG_4ADDR_AP | + WIPHY_FLAG_4ADDR_STATION; wiphy->privid = mac80211_wiphy_privid; /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 775365f856c..96f13ad05d3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1192,10 +1192,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr && - ieee80211_has_a4(hdr->frame_control)) + if (ieee80211_has_a4(hdr->frame_control) && + sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) return -1; - if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1)) + + if (is_multicast_ether_addr(hdr->addr1) && + ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) || + (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr))) return -1; return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); @@ -1245,7 +1248,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) if ((sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && - (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) { + (rx->flags & IEEE80211_RX_RA_MATCH) && + (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { if (is_multicast_ether_addr(ehdr->h_dest)) { /* * send multicast frames both to higher layers in @@ -2007,7 +2011,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: - if (!bssid && !sdata->use_4addr) + if (!bssid && !sdata->u.mgd.use_4addr) return 0; if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b3c1faeb592..5af2f40ea4d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1051,7 +1051,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, hdr = (struct ieee80211_hdr *) skb->data; - if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr) + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) tx->sta = rcu_dereference(sdata->u.vlan.sta); if (!tx->sta) tx->sta = sta_info_get(local, hdr->addr1); @@ -1632,8 +1632,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: rcu_read_lock(); - if (sdata->use_4addr) - sta = rcu_dereference(sdata->u.vlan.sta); + sta = rcu_dereference(sdata->u.vlan.sta); if (sta) { fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ @@ -1727,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, #endif case NL80211_IFTYPE_STATION: memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); - if (sdata->use_4addr && ethertype != ETH_P_PAE) { + if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) { fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); /* RA TA DA SA */ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6634188f945..b7b0f67b0c6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -968,6 +968,28 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) return 0; } +static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, + u8 use_4addr, enum nl80211_iftype iftype) +{ + if (!use_4addr) + return 0; + + switch (iftype) { + case NL80211_IFTYPE_AP_VLAN: + if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_AP) + return 0; + break; + case NL80211_IFTYPE_STATION: + if (rdev->wiphy.flags & WIPHY_FLAG_4ADDR_STATION) + return 0; + break; + default: + break; + } + + return -EOPNOTSUPP; +} + static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; @@ -1011,6 +1033,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_4ADDR]) { params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); change = true; + err = nl80211_valid_4addr(rdev, params.use_4addr, ntype); + if (err) + goto unlock; } else { params.use_4addr = -1; } @@ -1034,6 +1059,9 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) else err = 0; + if (!err && params.use_4addr != -1) + dev->ieee80211_ptr->use_4addr = params.use_4addr; + unlock: dev_put(dev); cfg80211_unlock_rdev(rdev); @@ -1081,8 +1109,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); } - if (info->attrs[NL80211_ATTR_4ADDR]) + if (info->attrs[NL80211_ATTR_4ADDR]) { params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); + err = nl80211_valid_4addr(rdev, params.use_4addr, type); + if (err) + goto unlock; + } err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, diff --git a/net/wireless/util.c b/net/wireless/util.c index 5aa39f7cf9b..17a7a4cfc61 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -659,6 +659,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return -EOPNOTSUPP; if (ntype != otype) { + dev->ieee80211_ptr->use_4addr = false; + switch (otype) { case NL80211_IFTYPE_ADHOC: cfg80211_leave_ibss(rdev, dev, false); @@ -682,5 +684,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); + if (!err && params && params->use_4addr != -1) + dev->ieee80211_ptr->use_4addr = params->use_4addr; + return err; } -- cgit v1.2.3 From ad4bb6f8883a13bb0f65b194dae36c62a02ac779 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 00:56:30 +0100 Subject: cfg80211: disallow bridging managed/adhoc interfaces A number of people have tried to add a wireless interface (in managed mode) to a bridge and then complained that it doesn't work. It cannot work, however, because in 802.11 networks all packets need to be acknowledged and as such need to be sent to the right address. Promiscuous doesn't help here. The wireless address format used for these links has only space for three addresses, the * transmitter, which must be equal to the sender (origin) * receiver (on the wireless medium), which is the AP in the case of managed mode * the recipient (destination), which is on the APs local network segment In an IBSS, it is similar, but the receiver and recipient must match and the third address is used as the BSSID. To avoid such mistakes in the future, disallow adding a wireless interface to a bridge. Felix has recently added a four-address mode to the AP and client side that can be used (after negotiating that it is possible, which must happen out-of-band by setting up both sides) for bridging, so allow that case. Signed-off-by: Johannes Berg Acked-by: Stephen Hemminger Signed-off-by: John W. Linville --- include/linux/if.h | 1 + net/bridge/br_if.c | 4 ++++ net/wireless/core.c | 4 ++++ net/wireless/nl80211.c | 12 ++++++++---- net/wireless/util.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/linux/if.h b/include/linux/if.h index 3b2a46bf8f8..3a9f410a296 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -70,6 +70,7 @@ #define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to * release skb->dst */ +#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */ #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index a6f74b2b957..a2cbe61f6e6 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (dev->br_port != NULL) return -EBUSY; + /* No bridging devices that dislike that (e.g. wireless) */ + if (dev->priv_flags & IFF_DONT_BRIDGE) + return -EOPNOTSUPP; + p = new_nbp(br, dev); if (IS_ERR(p)) return PTR_ERR(p); diff --git a/net/wireless/core.c b/net/wireless/core.c index e2cc6e7522d..fc5e9b50860 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -697,6 +697,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif if (!dev->ethtool_ops) dev->ethtool_ops = &cfg80211_ethtool_ops; + + if ((wdev->iftype == NL80211_IFTYPE_STATION || + wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) + dev->priv_flags |= IFF_DONT_BRIDGE; break; case NETDEV_GOING_DOWN: switch (wdev->iftype) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b7b0f67b0c6..149539ade15 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -969,10 +969,14 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) } static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, - u8 use_4addr, enum nl80211_iftype iftype) + struct net_device *netdev, u8 use_4addr, + enum nl80211_iftype iftype) { - if (!use_4addr) + if (!use_4addr) { + if (netdev && netdev->br_port) + return -EBUSY; return 0; + } switch (iftype) { case NL80211_IFTYPE_AP_VLAN: @@ -1033,7 +1037,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_4ADDR]) { params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); change = true; - err = nl80211_valid_4addr(rdev, params.use_4addr, ntype); + err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); if (err) goto unlock; } else { @@ -1111,7 +1115,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_4ADDR]) { params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); - err = nl80211_valid_4addr(rdev, params.use_4addr, type); + err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); if (err) goto unlock; } diff --git a/net/wireless/util.c b/net/wireless/util.c index 17a7a4cfc61..59361fdcb5d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -658,6 +658,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, !(rdev->wiphy.interface_modes & (1 << ntype))) return -EOPNOTSUPP; + /* if it's part of a bridge, reject changing type to station/ibss */ + if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC || + ntype == NL80211_IFTYPE_STATION)) + return -EBUSY; + if (ntype != otype) { dev->ieee80211_ptr->use_4addr = false; @@ -687,5 +692,31 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, if (!err && params && params->use_4addr != -1) dev->ieee80211_ptr->use_4addr = params->use_4addr; + if (!err) { + dev->priv_flags &= ~IFF_DONT_BRIDGE; + switch (ntype) { + case NL80211_IFTYPE_STATION: + if (dev->ieee80211_ptr->use_4addr) + break; + /* fall through */ + case NL80211_IFTYPE_ADHOC: + dev->priv_flags |= IFF_DONT_BRIDGE; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + /* bridging OK */ + break; + case NL80211_IFTYPE_MONITOR: + /* monitor can't bridge anyway */ + break; + case NL80211_IFTYPE_UNSPECIFIED: + case __NL80211_IFTYPE_AFTER_LAST: + /* not happening */ + break; + } + } + return err; } -- cgit v1.2.3 From 7351c6bd482712e5e3ec9dffc547de0e0863efb0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 01:08:30 +0100 Subject: mac80211: request TX status where needed Right now all frames mac80211 hands to the driver have the IEEE80211_TX_CTL_REQ_TX_STATUS flag set to request TX status. This isn't really necessary, only the injected frames need TX status (the latter for hostapd) so move setting this flag. The rate control algorithms also need TX status, but they don't require it. Also, rt2x00 uses that bit for its own purposes and seems to require it being set for all frames, but that can be fixed in rt2x00. This doesn't really change anything for any drivers but in the future drivers using hw-rate control may opt to not report TX status for frames that don't have the IEEE80211_TX_CTL_REQ_TX_STATUS flag set. Signed-off-by: Johannes Berg Acked-by: Ivo van Doorn [rt2x00 bits] Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 11 ++++++----- drivers/net/wireless/rt2x00/rt2x00lib.h | 4 +++- drivers/net/wireless/rt2x00/rt2x00mac.c | 5 ++--- drivers/net/wireless/rt2x00/rt2x00queue.c | 6 +++++- drivers/net/wireless/rt2x00/rt2x00queue.h | 5 ++++- include/net/mac80211.h | 2 +- net/mac80211/tx.c | 4 ++-- 7 files changed, 23 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 6c6d0ac3554..4a4b7e42fe6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -205,6 +205,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8 rate_idx, rate_flags, retry_rates; + u8 skbdesc_flags = skbdesc->flags; unsigned int i; bool success; @@ -287,12 +288,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, } /* - * Only send the status report to mac80211 when TX status was - * requested by it. If this was a extra frame coming through - * a mac80211 library call (RTS/CTS) then we should not send the - * status report back. + * Only send the status report to mac80211 when it's a frame + * that originated in mac80211. If this was a extra frame coming + * through a mac80211 library call (RTS/CTS) then we should not + * send the status report back. */ - if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) + if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); else dev_kfree_skb_irq(entry->skb); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index c1f48acaee4..be2e37fb407 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -162,8 +162,10 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length); * rt2x00queue_write_tx_frame - Write TX frame to hardware * @queue: Queue over which the frame should be send * @skb: The skb to send + * @local: frame is not from mac80211 */ -int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb); +int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, + bool local); /** * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index eed093d3453..9c90ceb0ffc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -66,7 +66,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, rts_info = IEEE80211_SKB_CB(skb); rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT; - rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; @@ -91,7 +90,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, frag_skb->data, data_length, tx_info, (struct ieee80211_rts *)(skb->data)); - retval = rt2x00queue_write_tx_frame(queue, skb); + retval = rt2x00queue_write_tx_frame(queue, skb, true); if (retval) { dev_kfree_skb_any(skb); WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); @@ -153,7 +152,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) goto exit_fail; } - if (rt2x00queue_write_tx_frame(queue, skb)) + if (rt2x00queue_write_tx_frame(queue, skb, false)) goto exit_fail; if (rt2x00queue_threshold(queue)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 02972a036bc..eaedee8c05c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -454,7 +454,8 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); } -int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) +int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, + bool local) { struct ieee80211_tx_info *tx_info; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); @@ -495,6 +496,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) skbdesc->tx_rate_idx = rate_idx; skbdesc->tx_rate_flags = rate_flags; + if (local) + skbdesc->flags |= SKBDESC_NOT_MAC80211; + /* * When hardware encryption is supported, and this frame * is to be encrypted, we should strip the IV/EIV data from diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 97c7895c0ec..70775e5ba1a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -94,12 +94,15 @@ enum data_queue_qid { * mac80211 but was stripped for processing by the driver. * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment, * the padded bytes are located between header and payload. + * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211, + * don't try to pass it back. */ enum skb_frame_desc_flags { SKBDESC_DMA_MAPPED_RX = 1 << 0, SKBDESC_DMA_MAPPED_TX = 1 << 1, SKBDESC_IV_STRIPPED = 1 << 2, - SKBDESC_L2_PADDED = 1 << 3 + SKBDESC_L2_PADDED = 1 << 3, + SKBDESC_NOT_MAC80211 = 1 << 4, }; /** diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f34f4ca7016..3754ea405c8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -219,7 +219,7 @@ struct ieee80211_bss_conf { * * These flags are used with the @flags member of &ieee80211_tx_info. * - * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. + * @IEEE80211_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence * number to this frame, taking care of not overwriting the fragment * number and increasing the sequence number only when the diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5af2f40ea4d..943def2b07d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1443,8 +1443,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); } - info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - rcu_read_lock(); if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { @@ -1575,6 +1573,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, memset(info, 0, sizeof(*info)); + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + /* pass the radiotap header up to xmit */ ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb); return NETDEV_TX_OK; -- cgit v1.2.3 From a58ce43f2fb17b728395ff530f019ca53c80145f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 12:45:42 +0100 Subject: mac80211: avoid spurious deauth frames/messages With WEXT, it happens frequently that the SME requests an authentication but then deauthenticates right away because some new parameters came along. Every time this happens we print a deauth message and send a deauth frame, but both of that is rather confusing. Avoid it by aborting the authentication process silently, and telling cfg80211 about that. The patch looks larger than it really is: __cfg80211_auth_remove() is split out from cfg80211_send_auth_timeout(), there's no new code except __cfg80211_auth_canceled() (a one-liner) and the mac80211 bits (7 new lines of code). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 12 ++++++++++++ net/mac80211/mlme.c | 17 +++++++++++++++++ net/wireless/mlme.c | 36 +++++++++++++++++++++++++----------- 3 files changed, 54 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d1e05aeb0c0..a6492e9bca9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1838,6 +1838,18 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); */ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); +/** + * __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled + * @dev: network device + * @addr: The MAC address of the device with which the authentication timed out + * + * When a pending authentication had no action yet, the driver may decide + * to not send a deauth frame, but in that case must calls this function + * to tell cfg80211 about this decision. It is only valid to call this + * function within the deauth() callback. + */ +void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr); + /** * cfg80211_send_rx_assoc - notification of processed association * @dev: network device diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f399547306c..6dc7b5ad9a4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2508,6 +2508,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_work *wk; const u8 *bssid = NULL; + bool not_auth_yet = false; mutex_lock(&ifmgd->mtx); @@ -2517,12 +2518,28 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } else list_for_each_entry(wk, &ifmgd->work_list, list) { if (&wk->bss->cbss == req->bss) { bssid = req->bss->bssid; + if (wk->state == IEEE80211_MGD_STATE_PROBE) + not_auth_yet = true; list_del(&wk->list); kfree(wk); break; } } + /* + * If somebody requests authentication and we haven't + * sent out an auth frame yet there's no need to send + * out a deauth frame either. If the state was PROBE, + * then this is the case. If it's AUTH we have sent a + * frame, and if it's IDLE we have completed the auth + * process already. + */ + if (not_auth_yet) { + mutex_unlock(&ifmgd->mtx); + __cfg80211_auth_canceled(sdata->dev, bssid); + return 0; + } + /* * cfg80211 should catch this ... but it's racy since * we can receive a deauth frame, process it, hand it diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 622af5649b9..1001db4912f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -243,21 +243,12 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) } EXPORT_SYMBOL(cfg80211_send_disassoc); -void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) +static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr) { - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); int i; bool done = false; - wdev_lock(wdev); - - nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); - if (wdev->sme_state == CFG80211_SME_CONNECTING) - __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - false, NULL); + ASSERT_WDEV_LOCK(wdev); for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { if (wdev->authtry_bsses[i] && @@ -272,6 +263,29 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) } WARN_ON(!done); +} + +void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr) +{ + __cfg80211_auth_remove(dev->ieee80211_ptr, addr); +} +EXPORT_SYMBOL(__cfg80211_auth_canceled); + +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + wdev_lock(wdev); + + nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); + if (wdev->sme_state == CFG80211_SME_CONNECTING) + __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + false, NULL); + + __cfg80211_auth_remove(wdev, addr); wdev_unlock(wdev); } -- cgit v1.2.3 From 64491f0ec8b653560a030022dccfce67ad353d81 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 14:26:11 +0100 Subject: mac80211: add per-station HT capability file This is sometimes useful to debug HT issues as it shows what exactly the stack thinks the peer supports. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index f043c29070d..3f41608c808 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -157,6 +157,34 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, } STA_OPS(agg_status); +static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[200], *p = buf; + int i; + struct sta_info *sta = file->private_data; + struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; + + p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n", + htc->ht_supported ? "" : "not "); + if (htc->ht_supported) { + p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap); + p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n", + htc->ampdu_factor, htc->ampdu_density); + p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:"); + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) + p += scnprintf(p, sizeof(buf)+buf-p, " %.2x", + htc->mcs.rx_mask[i]); + p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n", + le16_to_cpu(htc->mcs.rx_highest)); + p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n", + htc->mcs.tx_params); + } + + return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); +} +STA_OPS(ht_capa); + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); @@ -207,6 +235,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(last_signal); DEBUGFS_ADD(last_noise); DEBUGFS_ADD(wep_weak_iv_count); + DEBUGFS_ADD(ht_capa); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) -- cgit v1.2.3 From 9f13084d52d40dcce5a5f00586410acdb5a3fbff Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Thu, 19 Nov 2009 15:49:10 +0000 Subject: mac80211: fix endianess on mesh_path_error_tx() calls Signed-off-by: Rui Paulo Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 3fbabbf34ea..a8da23905c7 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -468,7 +468,7 @@ void mesh_plink_broken(struct sta_info *sta) spin_unlock_bh(&mpath->state_lock); mesh_path_error_tx(MESH_TTL, mpath->dst, cpu_to_le32(mpath->sn), - PERR_RCODE_DEST_UNREACH, + cpu_to_le16(PERR_RCODE_DEST_UNREACH), bcast, sdata); } else spin_unlock_bh(&mpath->state_lock); @@ -614,7 +614,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, if (mpath) sn = ++mpath->sn; mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn), - PERR_RCODE_NO_ROUTE, ra, sdata); + cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata); } kfree_skb(skb); -- cgit v1.2.3 From 8964be4a9a5ca8cab1219bb046db2f6d1936227c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 20 Nov 2009 15:35:04 -0800 Subject: net: rename skb->iif to skb->skb_iif To help grep games, rename iif to skb_iif Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/ieee802154/fakehard.c | 2 +- drivers/net/ifb.c | 6 +++--- include/linux/skbuff.h | 4 ++-- include/net/pkt_cls.h | 4 ++-- net/core/dev.c | 6 +++--- net/core/skbuff.c | 2 +- net/netlabel/netlabel_unlabeled.c | 2 +- net/sched/act_mirred.c | 2 +- net/sched/cls_flow.c | 2 +- security/selinux/hooks.c | 6 +++--- security/smack/smack_lsm.c | 4 ++-- 11 files changed, 20 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index f877f13e3ab..617549f30ef 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -282,7 +282,7 @@ static int ieee802154_fake_close(struct net_device *dev) static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) { - skb->iif = dev->ifindex; + skb->skb_iif = dev->ifindex; skb->dev = dev; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 69c25668dd6..f4081c0a2d9 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -99,7 +99,7 @@ static void ri_tasklet(unsigned long dev) stats->tx_bytes +=skb->len; rcu_read_lock(); - skb->dev = dev_get_by_index_rcu(&init_net, skb->iif); + skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif); if (!skb->dev) { rcu_read_unlock(); dev_kfree_skb(skb); @@ -107,7 +107,7 @@ static void ri_tasklet(unsigned long dev) break; } rcu_read_unlock(); - skb->iif = _dev->ifindex; + skb->skb_iif = _dev->ifindex; if (from & AT_EGRESS) { dp->st_rx_frm_egr++; @@ -172,7 +172,7 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) stats->rx_packets++; stats->rx_bytes+=skb->len; - if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->iif) { + if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) { dev_kfree_skb(skb); stats->rx_dropped++; return NETDEV_TX_OK; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 63f47426977..89eed8cdd31 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -299,7 +299,7 @@ typedef unsigned char *sk_buff_data_t; * @nfctinfo: Relationship of this skb to the connection * @nfct_reasm: netfilter conntrack re-assembly pointer * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c - * @iif: ifindex of device we arrived on + * @skb_iif: ifindex of device we arrived on * @queue_mapping: Queue mapping for multiqueue devices * @tc_index: Traffic control index * @tc_verd: traffic control verdict @@ -366,7 +366,7 @@ struct sk_buff { struct nf_bridge_info *nf_bridge; #endif - int iif; + int skb_iif; #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ #ifdef CONFIG_NET_CLS_ACT diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 3dd210d073c..dd3031aed9d 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -343,9 +343,9 @@ tcf_match_indev(struct sk_buff *skb, char *indev) struct net_device *dev; if (indev[0]) { - if (!skb->iif) + if (!skb->skb_iif) return 0; - dev = __dev_get_by_index(dev_net(skb->dev), skb->iif); + dev = __dev_get_by_index(dev_net(skb->dev), skb->skb_iif); if (!dev || strcmp(indev, dev->name)) return 0; } diff --git a/net/core/dev.c b/net/core/dev.c index 9977288583b..09f3d6b9c0c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2287,7 +2287,7 @@ static int ing_filter(struct sk_buff *skb) if (MAX_RED_LOOP < ttl++) { printk(KERN_WARNING "Redir loop detected Dropping packet (%d->%d)\n", - skb->iif, dev->ifindex); + skb->skb_iif, dev->ifindex); return TC_ACT_SHOT; } @@ -2395,8 +2395,8 @@ int netif_receive_skb(struct sk_buff *skb) if (netpoll_receive_skb(skb)) return NET_RX_DROP; - if (!skb->iif) - skb->iif = skb->dev->ifindex; + if (!skb->skb_iif) + skb->skb_iif = skb->dev->ifindex; null_or_orig = NULL; orig_dev = skb->dev; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 739b8f4dd32..bfa3e7865a8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -549,7 +549,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif new->protocol = old->protocol; new->mark = old->mark; - new->iif = old->iif; + new->skb_iif = old->skb_iif; __nf_copy(new, old); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 3dfe2bac862..98ed22ee2ff 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1550,7 +1550,7 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, struct netlbl_unlhsh_iface *iface; rcu_read_lock(); - iface = netlbl_unlhsh_search_iface_def(skb->iif); + iface = netlbl_unlhsh_search_iface_def(skb->skb_iif); if (iface == NULL) goto unlabel_getattr_nolabel; switch (family) { diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 79747936988..d329170243c 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -185,7 +185,7 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); skb2->dev = dev; - skb2->iif = skb->dev->ifindex; + skb2->skb_iif = skb->dev->ifindex; dev_queue_xmit(skb2); err = 0; diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 9402a7fd378..e054c62857e 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -171,7 +171,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb) static u32 flow_get_iif(const struct sk_buff *skb) { - return skb->iif; + return skb->skb_iif; } static u32 flow_get_priority(const struct sk_buff *skb) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index bb230d5d708..83a4aada0b4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4085,7 +4085,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, char *addrp; COMMON_AUDIT_DATA_INIT(&ad, NET); - ad.u.net.netif = skb->iif; + ad.u.net.netif = skb->skb_iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); if (err) @@ -4147,7 +4147,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) return 0; COMMON_AUDIT_DATA_INIT(&ad, NET); - ad.u.net.netif = skb->iif; + ad.u.net.netif = skb->skb_iif; ad.u.net.family = family; err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); if (err) @@ -4159,7 +4159,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); if (err) return err; - err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, + err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family, peer_sid, &ad); if (err) { selinux_netlbl_err(skb, err, 0); diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c33b6bb9b6d..529c9ca6587 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2602,7 +2602,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); ad.a.u.net.family = sk->sk_family; - ad.a.u.net.netif = skb->iif; + ad.a.u.net.netif = skb->skb_iif; ipv4_skb_to_auditdata(skb, &ad.a, NULL); #endif /* @@ -2757,7 +2757,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); ad.a.u.net.family = family; - ad.a.u.net.netif = skb->iif; + ad.a.u.net.netif = skb->skb_iif; ipv4_skb_to_auditdata(skb, &ad.a, NULL); #endif /* -- cgit v1.2.3 From e994b7c901ded7200b525a707c6da71f2cf6d4bb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 21 Nov 2009 11:22:25 -0800 Subject: tcp: Don't make syn cookies initial setting depend on CONFIG_SYSCTL That's extremely non-intuitive, noticed by William Allen Simpson. And let's make the default be on, it's been suggested by a lot of people so we'll give it a try. Signed-off-by: David S. Miller --- net/ipv4/tcp_minisocks.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4be22280e6b..ab32c181f74 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -26,13 +26,7 @@ #include #include -#ifdef CONFIG_SYSCTL -#define SYNC_INIT 0 /* let the user enable it */ -#else -#define SYNC_INIT 1 -#endif - -int sysctl_tcp_syncookies __read_mostly = SYNC_INIT; +int sysctl_tcp_syncookies __read_mostly = 1; EXPORT_SYMBOL(sysctl_tcp_syncookies); int sysctl_tcp_abort_on_overflow __read_mostly; -- cgit v1.2.3 From 6ebfbc065624790772398f5b327ac33a7ae3880b Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 22 Nov 2009 20:43:13 -0800 Subject: net: Fix missing kernel-doc notation Fix the following htmldocs warning: Warning(net/core/dev.c:5378): bad line: Signed-off-by: Jaswinder Singh Rajput Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 09f3d6b9c0c..ccefa2473c3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5375,7 +5375,7 @@ EXPORT_SYMBOL(synchronize_net); * unregister_netdevice_queue - remove device from the kernel * @dev: device * @head: list - + * * This function shuts down a device interface and removes it * from the kernel tables. * If head not NULL, device is queued to be unregistered later. -- cgit v1.2.3 From c4832c7bbc3f7a4813347e871d7238651bf437d3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 23 Nov 2009 10:34:39 +0100 Subject: netfilter: nf_ct_tcp: improve out-of-sync situation in TCP tracking Without this patch, if we receive a SYN packet from the client while the firewall is out-of-sync, we let it go through. Then, if we see the SYN/ACK reply coming from the server, we destroy the conntrack entry and drop the packet to trigger a new retransmission. Then, the retransmision from the client is used to start a new clean session. This patch improves the current handling. Basically, if we see an unexpected SYN packet, we annotate the TCP options. Then, if we see the reply SYN/ACK, this means that the firewall was indeed out-of-sync. Therefore, we set a clean new session from the existing entry based on the annotated values. This patch adds two new 8-bits fields that fit in a 16-bits gap of the ip_ct_tcp structure. This patch is particularly useful for conntrackd since the asynchronous nature of the state-synchronization allows to have backup nodes that are not perfect copies of the master. This helps to improve the recovery under some worst-case scenarios. I have tested this by creating lots of conntrack entries in wrong state: for ((i=1024;i<65535;i++)); do conntrack -I -p tcp -s 192.168.2.101 -d 192.168.2.2 --sport $i --dport 80 -t 800 --state ESTABLISHED -u ASSURED,SEEN_REPLY; done Then, I make some TCP connections: $ echo GET / | nc 192.168.2.2 80 The events show the result: [UPDATE] tcp 6 60 SYN_RECV src=192.168.2.101 dst=192.168.2.2 sport=33220 dport=80 src=192.168.2.2 dst=192.168.2.101 sport=80 dport=33220 [ASSURED] [UPDATE] tcp 6 432000 ESTABLISHED src=192.168.2.101 dst=192.168.2.2 sport=33220 dport=80 src=192.168.2.2 dst=192.168.2.101 sport=80 dport=33220 [ASSURED] [UPDATE] tcp 6 120 FIN_WAIT src=192.168.2.101 dst=192.168.2.2 sport=33220 dport=80 src=192.168.2.2 dst=192.168.2.101 sport=80 dport=33220 [ASSURED] [UPDATE] tcp 6 30 LAST_ACK src=192.168.2.101 dst=192.168.2.2 sport=33220 dport=80 src=192.168.2.2 dst=192.168.2.101 sport=80 dport=33220 [ASSURED] [UPDATE] tcp 6 120 TIME_WAIT src=192.168.2.101 dst=192.168.2.2 sport=33220 dport=80 src=192.168.2.2 dst=192.168.2.101 sport=80 dport=33220 [ASSURED] and tcpdump shows no retransmissions: 20:47:57.271951 IP 192.168.2.101.33221 > 192.168.2.2.www: S 435402517:435402517(0) win 5840 20:47:57.273538 IP 192.168.2.2.www > 192.168.2.101.33221: S 3509927945:3509927945(0) ack 435402518 win 5792 20:47:57.273608 IP 192.168.2.101.33221 > 192.168.2.2.www: . ack 3509927946 win 92 20:47:57.273693 IP 192.168.2.101.33221 > 192.168.2.2.www: P 435402518:435402524(6) ack 3509927946 win 92 20:47:57.275492 IP 192.168.2.2.www > 192.168.2.101.33221: . ack 435402524 win 362 20:47:57.276492 IP 192.168.2.2.www > 192.168.2.101.33221: P 3509927946:3509928082(136) ack 435402524 win 362 20:47:57.276515 IP 192.168.2.101.33221 > 192.168.2.2.www: . ack 3509928082 win 108 20:47:57.276521 IP 192.168.2.2.www > 192.168.2.101.33221: F 3509928082:3509928082(0) ack 435402524 win 362 20:47:57.277369 IP 192.168.2.101.33221 > 192.168.2.2.www: F 435402524:435402524(0) ack 3509928083 win 108 20:47:57.279491 IP 192.168.2.2.www > 192.168.2.101.33221: . ack 435402525 win 362 I also added a rule to log invalid packets, with no occurrences :-) . Signed-off-by: Pablo Neira Ayuso Acked-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_tcp.h | 3 ++ net/netfilter/nf_conntrack_proto_tcp.c | 51 ++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h index 4352feed237..ece22e94dcb 100644 --- a/include/linux/netfilter/nf_conntrack_tcp.h +++ b/include/linux/netfilter/nf_conntrack_tcp.h @@ -67,6 +67,9 @@ struct ip_ct_tcp u_int32_t last_ack; /* Last sequence number seen in opposite dir */ u_int32_t last_end; /* Last seq + len */ u_int16_t last_win; /* Last window advertisement seen in dir */ + /* For SYN packets while we may be out-of-sync */ + u_int8_t last_wscale; /* Last window scaling factor seen */ + u_int8_t last_flags; /* Last flags set */ }; #endif /* __KERNEL__ */ diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 97a82ba7537..9cc6b5cb06a 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -908,23 +908,54 @@ static int tcp_packet(struct nf_conn *ct, /* b) This SYN/ACK acknowledges a SYN that we earlier * ignored as invalid. This means that the client and * the server are both in sync, while the firewall is - * not. We kill this session and block the SYN/ACK so - * that the client cannot but retransmit its SYN and - * thus initiate a clean new session. + * not. We get in sync from the previously annotated + * values. */ - spin_unlock_bh(&ct->lock); - if (LOG_INVALID(net, IPPROTO_TCP)) - nf_log_packet(pf, 0, skb, NULL, NULL, NULL, - "nf_ct_tcp: killing out of sync session "); - nf_ct_kill(ct); - return NF_DROP; + old_state = TCP_CONNTRACK_SYN_SENT; + new_state = TCP_CONNTRACK_SYN_RECV; + ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_end = + ct->proto.tcp.last_end; + ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxend = + ct->proto.tcp.last_end; + ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxwin = + ct->proto.tcp.last_win == 0 ? + 1 : ct->proto.tcp.last_win; + ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale = + ct->proto.tcp.last_wscale; + ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = + ct->proto.tcp.last_flags; + memset(&ct->proto.tcp.seen[dir], 0, + sizeof(struct ip_ct_tcp_state)); + break; } ct->proto.tcp.last_index = index; ct->proto.tcp.last_dir = dir; ct->proto.tcp.last_seq = ntohl(th->seq); ct->proto.tcp.last_end = segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th); - + ct->proto.tcp.last_win = ntohs(th->window); + + /* a) This is a SYN in ORIGINAL. The client and the server + * may be in sync but we are not. In that case, we annotate + * the TCP options and let the packet go through. If it is a + * valid SYN packet, the server will reply with a SYN/ACK, and + * then we'll get in sync. Otherwise, the server ignores it. */ + if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) { + struct ip_ct_tcp_state seen = {}; + + ct->proto.tcp.last_flags = + ct->proto.tcp.last_wscale = 0; + tcp_options(skb, dataoff, th, &seen); + if (seen.flags & IP_CT_TCP_FLAG_WINDOW_SCALE) { + ct->proto.tcp.last_flags |= + IP_CT_TCP_FLAG_WINDOW_SCALE; + ct->proto.tcp.last_wscale = seen.td_scale; + } + if (seen.flags & IP_CT_TCP_FLAG_SACK_PERM) { + ct->proto.tcp.last_flags |= + IP_CT_TCP_FLAG_SACK_PERM; + } + } spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, -- cgit v1.2.3 From 3a0429292daa0e1ec848bd26479f5e48b0d54a42 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 23 Nov 2009 10:43:57 +0100 Subject: netfilter: xtables: fix conntrack match v1 ipt-save output commit d6d3f08b0fd998b647a05540cedd11a067b72867 (netfilter: xtables: conntrack match revision 2) does break the v1 conntrack match iptables-save output in a subtle way. Problem is as follows: up = kmalloc(sizeof(*up), GFP_KERNEL); [..] /* * The strategy here is to minimize the overhead of v1 matching, * by prebuilding a v2 struct and putting the pointer into the * v1 dataspace. */ memcpy(up, info, offsetof(typeof(*info), state_mask)); [..] *(void **)info = up; As the v2 struct pointer is saved in the match data space, it clobbers the first structure member (->origsrc_addr). Because the _v1 match function grabs this pointer and does not actually look at the v1 origsrc, run time functionality does not break. But iptables -nvL (or iptables-save) cannot know that v1 origsrc_addr has been overloaded in this way: $ iptables -p tcp -A OUTPUT -m conntrack --ctorigsrc 10.0.0.1 -j ACCEPT $ iptables-save -A OUTPUT -p tcp -m conntrack --ctorigsrc 128.173.134.206 -j ACCEPT (128.173... is the address to the v2 match structure). To fix this, we take advantage of the fact that the v1 and v2 structures are identical with exception of the last two structure members (u8 in v1, u16 in v2). We extract them as early as possible and prevent the v2 matching function from looking at those two members directly. Previously reported by Michel Messerschmidt via Ben Hutchings, also see Debian Bug tracker #556587. Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy --- net/netfilter/xt_conntrack.c | 61 ++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) (limited to 'net') diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 6dc4652f2fe..ae66305f0fe 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -113,7 +113,8 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info, } static bool -conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) +conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par, + u16 state_mask, u16 status_mask) { const struct xt_conntrack_mtinfo2 *info = par->matchinfo; enum ip_conntrack_info ctinfo; @@ -136,7 +137,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (test_bit(IPS_DST_NAT_BIT, &ct->status)) statebit |= XT_CONNTRACK_STATE_DNAT; } - if (!!(info->state_mask & statebit) ^ + if (!!(state_mask & statebit) ^ !(info->invert_flags & XT_CONNTRACK_STATE)) return false; } @@ -172,7 +173,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) return false; if ((info->match_flags & XT_CONNTRACK_STATUS) && - (!!(info->status_mask & ct->status) ^ + (!!(status_mask & ct->status) ^ !(info->invert_flags & XT_CONNTRACK_STATUS))) return false; @@ -192,11 +193,17 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) static bool conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) { - const struct xt_conntrack_mtinfo2 *const *info = par->matchinfo; - struct xt_match_param newpar = *par; + const struct xt_conntrack_mtinfo1 *info = par->matchinfo; - newpar.matchinfo = *info; - return conntrack_mt(skb, &newpar); + return conntrack_mt(skb, par, info->state_mask, info->status_mask); +} + +static bool +conntrack_mt_v2(const struct sk_buff *skb, const struct xt_match_param *par) +{ + const struct xt_conntrack_mtinfo2 *info = par->matchinfo; + + return conntrack_mt(skb, par, info->state_mask, info->status_mask); } static bool conntrack_mt_check(const struct xt_mtchk_param *par) @@ -209,45 +216,11 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par) return true; } -static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par) -{ - struct xt_conntrack_mtinfo1 *info = par->matchinfo; - struct xt_conntrack_mtinfo2 *up; - int ret = conntrack_mt_check(par); - - if (ret < 0) - return ret; - - up = kmalloc(sizeof(*up), GFP_KERNEL); - if (up == NULL) { - nf_ct_l3proto_module_put(par->family); - return -ENOMEM; - } - - /* - * The strategy here is to minimize the overhead of v1 matching, - * by prebuilding a v2 struct and putting the pointer into the - * v1 dataspace. - */ - memcpy(up, info, offsetof(typeof(*info), state_mask)); - up->state_mask = info->state_mask; - up->status_mask = info->status_mask; - *(void **)info = up; - return true; -} - static void conntrack_mt_destroy(const struct xt_mtdtor_param *par) { nf_ct_l3proto_module_put(par->family); } -static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par) -{ - struct xt_conntrack_mtinfo2 **info = par->matchinfo; - kfree(*info); - conntrack_mt_destroy(par); -} - static struct xt_match conntrack_mt_reg[] __read_mostly = { { .name = "conntrack", @@ -255,8 +228,8 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = { .family = NFPROTO_UNSPEC, .matchsize = sizeof(struct xt_conntrack_mtinfo1), .match = conntrack_mt_v1, - .checkentry = conntrack_mt_check_v1, - .destroy = conntrack_mt_destroy_v1, + .checkentry = conntrack_mt_check, + .destroy = conntrack_mt_destroy, .me = THIS_MODULE, }, { @@ -264,7 +237,7 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = { .revision = 2, .family = NFPROTO_UNSPEC, .matchsize = sizeof(struct xt_conntrack_mtinfo2), - .match = conntrack_mt, + .match = conntrack_mt_v2, .checkentry = conntrack_mt_check, .destroy = conntrack_mt_destroy, .me = THIS_MODULE, -- cgit v1.2.3 From 9d4fb27db90043cd2640e4bc778f9c755d3c17c1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 23 Nov 2009 10:41:23 -0800 Subject: net/ipv4: Move && and || to end of previous line On Sun, 2009-11-22 at 16:31 -0800, David Miller wrote: > It should be of the form: > if (x && > y) > > or: > if (x && y) > > Fix patches, rather than complaints, for existing cases where things > do not follow this pattern are certainly welcome. Also collapsed some multiple tabs to single space. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/ipv4/inet_lro.c | 36 ++++++++++++++++++------------------ net/ipv4/ip_output.c | 6 ++++-- net/ipv4/ipconfig.c | 13 ++++++------- net/ipv4/route.c | 19 ++++++++++--------- net/ipv4/tcp_htcp.c | 10 +++++----- net/ipv4/tcp_input.c | 4 ++-- net/ipv4/tcp_lp.c | 4 ++-- net/ipv4/tcp_output.c | 4 ++-- net/ipv4/tcp_probe.c | 4 ++-- net/ipv4/tcp_veno.c | 5 ++--- net/ipv4/tcp_yeah.c | 4 ++-- net/ipv4/udp.c | 36 ++++++++++++++++++------------------ 12 files changed, 73 insertions(+), 72 deletions(-) (limited to 'net') diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c index 6a667dae315..47038cb6c13 100644 --- a/net/ipv4/inet_lro.c +++ b/net/ipv4/inet_lro.c @@ -64,15 +64,15 @@ static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph, if (iph->ihl != IPH_LEN_WO_OPTIONS) return -1; - if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack - || tcph->rst || tcph->syn || tcph->fin) + if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack || + tcph->rst || tcph->syn || tcph->fin) return -1; if (INET_ECN_is_ce(ipv4_get_dsfield(iph))) return -1; - if (tcph->doff != TCPH_LEN_WO_OPTIONS - && tcph->doff != TCPH_LEN_W_TIMESTAMP) + if (tcph->doff != TCPH_LEN_WO_OPTIONS && + tcph->doff != TCPH_LEN_W_TIMESTAMP) return -1; /* check tcp options (only timestamp allowed) */ @@ -262,10 +262,10 @@ static int lro_check_tcp_conn(struct net_lro_desc *lro_desc, struct iphdr *iph, struct tcphdr *tcph) { - if ((lro_desc->iph->saddr != iph->saddr) - || (lro_desc->iph->daddr != iph->daddr) - || (lro_desc->tcph->source != tcph->source) - || (lro_desc->tcph->dest != tcph->dest)) + if ((lro_desc->iph->saddr != iph->saddr) || + (lro_desc->iph->daddr != iph->daddr) || + (lro_desc->tcph->source != tcph->source) || + (lro_desc->tcph->dest != tcph->dest)) return -1; return 0; } @@ -339,9 +339,9 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, u64 flags; int vlan_hdr_len = 0; - if (!lro_mgr->get_skb_header - || lro_mgr->get_skb_header(skb, (void *)&iph, (void *)&tcph, - &flags, priv)) + if (!lro_mgr->get_skb_header || + lro_mgr->get_skb_header(skb, (void *)&iph, (void *)&tcph, + &flags, priv)) goto out; if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) @@ -351,8 +351,8 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, if (!lro_desc) goto out; - if ((skb->protocol == htons(ETH_P_8021Q)) - && !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID)) + if ((skb->protocol == htons(ETH_P_8021Q)) && + !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID)) vlan_hdr_len = VLAN_HLEN; if (!lro_desc->active) { /* start new lro session */ @@ -446,9 +446,9 @@ static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr, int hdr_len = LRO_MAX_PG_HLEN; int vlan_hdr_len = 0; - if (!lro_mgr->get_frag_header - || lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph, - (void *)&tcph, &flags, priv)) { + if (!lro_mgr->get_frag_header || + lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph, + (void *)&tcph, &flags, priv)) { mac_hdr = page_address(frags->page) + frags->page_offset; goto out1; } @@ -472,8 +472,8 @@ static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr, if (!skb) goto out; - if ((skb->protocol == htons(ETH_P_8021Q)) - && !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID)) + if ((skb->protocol == htons(ETH_P_8021Q)) && + !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID)) vlan_hdr_len = VLAN_HLEN; iph = (void *)(skb->data + vlan_hdr_len); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 322b40864ac..b78e61502ef 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -264,9 +264,11 @@ int ip_mc_output(struct sk_buff *skb) This check is duplicated in ip_mr_input at the moment. */ - && ((rt->rt_flags&RTCF_LOCAL) || !(IPCB(skb)->flags&IPSKB_FORWARDED)) + && + ((rt->rt_flags & RTCF_LOCAL) || + !(IPCB(skb)->flags & IPSKB_FORWARDED)) #endif - ) { + ) { struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); if (newskb) NF_HOOK(PF_INET, NF_INET_POST_ROUTING, newskb, diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index f8d04c25645..4e08b7f2331 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1172,10 +1172,9 @@ static int __init ic_dynamic(void) schedule_timeout_uninterruptible(1); #ifdef IPCONFIG_DHCP /* DHCP isn't done until we get a DHCPACK. */ - if ((ic_got_reply & IC_BOOTP) - && (ic_proto_enabled & IC_USE_DHCP) - && ic_dhcp_msgtype != DHCPACK) - { + if ((ic_got_reply & IC_BOOTP) && + (ic_proto_enabled & IC_USE_DHCP) && + ic_dhcp_msgtype != DHCPACK) { ic_got_reply = 0; printk(","); continue; @@ -1344,9 +1343,9 @@ static int __init ip_auto_config(void) */ if (ic_myaddr == NONE || #ifdef CONFIG_ROOT_NFS - (root_server_addr == NONE - && ic_servaddr == NONE - && ROOT_DEV == Root_NFS) || + (root_server_addr == NONE && + ic_servaddr == NONE && + ROOT_DEV == Root_NFS) || #endif ic_first_dev->next) { #ifdef IPCONFIG_DYNAMIC diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4284ceef794..7547944ea9b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1346,9 +1346,9 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, return; net = dev_net(dev); - if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) - || ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) - || ipv4_is_zeronet(new_gw)) + if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || + ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) || + ipv4_is_zeronet(new_gw)) goto reject_redirect; if (!rt_caching(net)) @@ -2311,10 +2311,11 @@ skip_cache: ip_hdr(skb)->protocol); if (our #ifdef CONFIG_IP_MROUTE - || (!ipv4_is_local_multicast(daddr) && - IN_DEV_MFORWARD(in_dev)) + || + (!ipv4_is_local_multicast(daddr) && + IN_DEV_MFORWARD(in_dev)) #endif - ) { + ) { rcu_read_unlock(); return ip_route_input_mc(skb, daddr, saddr, tos, dev, our); @@ -2511,9 +2512,9 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, of another iface. --ANK */ - if (oldflp->oif == 0 - && (ipv4_is_multicast(oldflp->fl4_dst) || - oldflp->fl4_dst == htonl(0xFFFFFFFF))) { + if (oldflp->oif == 0 && + (ipv4_is_multicast(oldflp->fl4_dst) || + oldflp->fl4_dst == htonl(0xFFFFFFFF))) { /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = ip_dev_find(net, oldflp->fl4_src); if (dev_out == NULL) diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 26d5c7fc7de..7c94a495541 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -92,8 +92,8 @@ static inline void measure_rtt(struct sock *sk, u32 srtt) if (icsk->icsk_ca_state == TCP_CA_Open) { if (ca->maxRTT < ca->minRTT) ca->maxRTT = ca->minRTT; - if (ca->maxRTT < srtt - && srtt <= ca->maxRTT + msecs_to_jiffies(20)) + if (ca->maxRTT < srtt && + srtt <= ca->maxRTT + msecs_to_jiffies(20)) ca->maxRTT = srtt; } } @@ -123,9 +123,9 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked, s32 rtt ca->packetcount += pkts_acked; - if (ca->packetcount >= tp->snd_cwnd - (ca->alpha >> 7 ? : 1) - && now - ca->lasttime >= ca->minRTT - && ca->minRTT > 0) { + if (ca->packetcount >= tp->snd_cwnd - (ca->alpha >> 7 ? : 1) && + now - ca->lasttime >= ca->minRTT && + ca->minRTT > 0) { __u32 cur_Bi = ca->packetcount * HZ / (now - ca->lasttime); if (htcp_ccount(ca) <= 3) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cc306ac6eb5..be166e0e11c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4852,11 +4852,11 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) struct tcp_sock *tp = tcp_sk(sk); /* More than one full frame received... */ - if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss + if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && /* ... and right edge of window advances far enough. * (tcp_recvmsg() will send ACK otherwise). Or... */ - && __tcp_select_window(sk) >= tp->rcv_wnd) || + __tcp_select_window(sk) >= tp->rcv_wnd) || /* We ACK each frame or... */ tcp_in_quickack_mode(sk) || /* We have out of order data. */ diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c index ce3c41ff50b..de870377fbb 100644 --- a/net/ipv4/tcp_lp.c +++ b/net/ipv4/tcp_lp.c @@ -143,8 +143,8 @@ static u32 tcp_lp_remote_hz_estimator(struct sock *sk) goto out; /* we can't calc remote HZ with no different!! */ - if (tp->rx_opt.rcv_tsval == lp->remote_ref_time - || tp->rx_opt.rcv_tsecr == lp->local_ref_time) + if (tp->rx_opt.rcv_tsval == lp->remote_ref_time || + tp->rx_opt.rcv_tsecr == lp->local_ref_time) goto out; m = HZ * (tp->rx_opt.rcv_tsval - diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 616c686ca25..875bc6dcd92 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1923,8 +1923,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) * case, when window is shrunk to zero. In this case * our retransmit serves as a zero window probe. */ - if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp)) - && TCP_SKB_CB(skb)->seq != tp->snd_una) + if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp)) && + TCP_SKB_CB(skb)->seq != tp->snd_una) return -EAGAIN; if (skb->len > cur_mss) { diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 7a3cc2ffad8..bb110c5ce1d 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -95,8 +95,8 @@ static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb, /* Only update if port matches */ if ((port == 0 || ntohs(inet->inet_dport) == port || - ntohs(inet->inet_sport) == port) - && (full || tp->snd_cwnd != tcp_probe.lastcwnd)) { + ntohs(inet->inet_sport) == port) && + (full || tp->snd_cwnd != tcp_probe.lastcwnd)) { spin_lock(&tcp_probe.lock); /* If log fills, just silently drop */ diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index e9bbff74648..b612acf7618 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -165,9 +165,8 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) * every other rtt. */ if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { - if (veno->inc - && tp->snd_cwnd < - tp->snd_cwnd_clamp) { + if (veno->inc && + tp->snd_cwnd < tp->snd_cwnd_clamp) { tp->snd_cwnd++; veno->inc = 0; } else diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index 66b6821b984..a0f24035889 100644 --- a/net/ipv4/tcp_yeah.c +++ b/net/ipv4/tcp_yeah.c @@ -157,8 +157,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) if (queue > TCP_YEAH_ALPHA || rtt - yeah->vegas.baseRTT > (yeah->vegas.baseRTT / TCP_YEAH_PHY)) { - if (queue > TCP_YEAH_ALPHA - && tp->snd_cwnd > yeah->reno_count) { + if (queue > TCP_YEAH_ALPHA && + tp->snd_cwnd > yeah->reno_count) { u32 reduction = min(queue / TCP_YEAH_GAMMA , tp->snd_cwnd >> TCP_YEAH_EPSILON); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 1eaf57567eb..1f9534846ca 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -136,12 +136,12 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num, struct hlist_nulls_node *node; sk_nulls_for_each(sk2, node, &hslot->head) - if (net_eq(sock_net(sk2), net) && - sk2 != sk && + if (net_eq(sock_net(sk2), net) && + sk2 != sk && (bitmap || udp_sk(sk2)->udp_port_hash == num) && - (!sk2->sk_reuse || !sk->sk_reuse) && - (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if - || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && + (!sk2->sk_reuse || !sk->sk_reuse) && + (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || + sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && (*saddr_comp)(sk, sk2)) { if (bitmap) __set_bit(udp_sk(sk2)->udp_port_hash >> log, @@ -168,12 +168,12 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num, spin_lock(&hslot2->lock); udp_portaddr_for_each_entry(sk2, node, &hslot2->head) - if (net_eq(sock_net(sk2), net) && - sk2 != sk && - (udp_sk(sk2)->udp_port_hash == num) && - (!sk2->sk_reuse || !sk->sk_reuse) && - (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if - || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && + if (net_eq(sock_net(sk2), net) && + sk2 != sk && + (udp_sk(sk2)->udp_port_hash == num) && + (!sk2->sk_reuse || !sk->sk_reuse) && + (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || + sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && (*saddr_comp)(sk, sk2)) { res = 1; break; @@ -545,13 +545,13 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, sk_nulls_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); - if (!net_eq(sock_net(s), net) || - udp_sk(s)->udp_port_hash != hnum || - (inet->inet_daddr && inet->inet_daddr != rmt_addr) || - (inet->inet_dport != rmt_port && inet->inet_dport) || - (inet->inet_rcv_saddr && - inet->inet_rcv_saddr != loc_addr) || - ipv6_only_sock(s) || + if (!net_eq(sock_net(s), net) || + udp_sk(s)->udp_port_hash != hnum || + (inet->inet_daddr && inet->inet_daddr != rmt_addr) || + (inet->inet_dport != rmt_port && inet->inet_dport) || + (inet->inet_rcv_saddr && + inet->inet_rcv_saddr != loc_addr) || + ipv6_only_sock(s) || (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) continue; if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) -- cgit v1.2.3 From 6dc7694f9df20f148076d82d00cb3663afb0b000 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 23 Nov 2009 15:53:53 -0500 Subject: sctp: implement the receiver side for SACK-IMMEDIATELY extension This patch implement the receiver side for SACK-IMMEDIATELY extension: Section 4.2. Receiver Side Considerations On reception of an SCTP packet containing a DATA chunk with the I-bit set, the receiver SHOULD NOT delay the sending of the corresponding SACK chunk and SHOULD send it back immediately. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- net/sctp/sm_statefuns.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index d4df45022ff..8ee24c9dc7e 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2868,6 +2868,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; + sctp_arg_t force = SCTP_NOFORCE(); int error; if (!sctp_vtag_verify(chunk, asoc)) { @@ -2901,6 +2902,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, BUG(); } + if (chunk->chunk_hdr->flags & SCTP_DATA_SACK_IMM) + force = SCTP_FORCE(); + if (asoc->autoclose) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); @@ -2929,7 +2933,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, * more aggressive than the following algorithms allow. */ if (chunk->end_of_packet) - sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, force); return SCTP_DISPOSITION_CONSUME; @@ -2954,7 +2958,7 @@ discard_force: discard_noforce: if (chunk->end_of_packet) - sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, force); return SCTP_DISPOSITION_DISCARD; consume: -- cgit v1.2.3 From b93d6471748de2ce02cc24774b774deb306a57a8 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 23 Nov 2009 15:53:56 -0500 Subject: sctp: implement the sender side for SACK-IMMEDIATELY extension This patch implement the sender side for SACK-IMMEDIATELY extension. Section 4.1. Sender Side Considerations Whenever the sender of a DATA chunk can benefit from the corresponding SACK chunk being sent back without delay, the sender MAY set the I-bit in the DATA chunk header. Reasons for setting the I-bit include o The sender is in the SHUTDOWN-PENDING state. o The application requests to set the I-bit of the last DATA chunk of a user message when providing the user message to the SCTP implementation. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich --- include/net/sctp/user.h | 1 + net/sctp/chunk.c | 15 ++++++++++++++- net/sctp/outqueue.c | 7 +++++++ 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index be2334aaf52..50b2431405f 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -206,6 +206,7 @@ enum sctp_sinfo_flags { SCTP_UNORDERED = 1, /* Send/receive message unordered. */ SCTP_ADDR_OVER = 2, /* Override the primary destination. */ SCTP_ABORT=4, /* Send an ABORT message to the peer. */ + SCTP_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */ SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */ }; diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index acf7c4d128f..8e4320040f0 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -263,9 +263,18 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, if (0 == i) frag |= SCTP_DATA_FIRST_FRAG; - if ((i == (whole - 1)) && !over) + if ((i == (whole - 1)) && !over) { frag |= SCTP_DATA_LAST_FRAG; + /* The application requests to set the I-bit of the + * last DATA chunk of a user message when providing + * the user message to the SCTP implementation. + */ + if ((sinfo->sinfo_flags & SCTP_EOF) || + (sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY)) + frag |= SCTP_DATA_SACK_IMM; + } + chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); if (!chunk) @@ -297,6 +306,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, else frag = SCTP_DATA_LAST_FRAG; + if ((sinfo->sinfo_flags & SCTP_EOF) || + (sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY)) + frag |= SCTP_DATA_SACK_IMM; + chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); if (!chunk) diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index c9f20e28521..5732661c87d 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1011,6 +1011,13 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) break; case SCTP_XMIT_OK: + /* The sender is in the SHUTDOWN-PENDING state, + * The sender MAY set the I-bit in the DATA + * chunk header. + */ + if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) + chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM; + break; default: -- cgit v1.2.3 From 6383cfb3ed3c5c0bea06da0099c219ef4237ecf5 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 23 Nov 2009 15:53:56 -0500 Subject: sctp: Fix malformed "Invalid Stream Identifier" error The "Invalid Stream Identifier" error has a 16 bit reserved field at the end, thus making the parameter length be 8 bytes. We've never supplied that reserved field making wireshark tag the packet as malformed. Reported-by: Chris Dischino Signed-off-by: Vlad Yasevich --- include/net/sctp/sm.h | 3 ++- net/sctp/sm_make_chunk.c | 13 +++++++++---- net/sctp/sm_statefuns.c | 13 ++++++++----- 3 files changed, 19 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index c1dd8936583..851c813adb3 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -243,7 +243,8 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *, const struct sctp_chunk *chunk, __be16 cause_code, const void *payload, - size_t paylen); + size_t paylen, + size_t reserve_tail); struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, union sctp_addr *, diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 9d881a61ac0..9e732916b67 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -987,7 +987,10 @@ static void *sctp_addto_param(struct sctp_chunk *chunk, int len, target = skb_put(chunk->skb, len); - memcpy(target, data, len); + if (data) + memcpy(target, data, len); + else + memset(target, 0, len); /* Adjust the chunk length field. */ chunk->chunk_hdr->length = htons(chunklen + len); @@ -1129,16 +1132,18 @@ nodata: struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, const struct sctp_chunk *chunk, __be16 cause_code, const void *payload, - size_t paylen) + size_t paylen, size_t reserve_tail) { struct sctp_chunk *retval; - retval = sctp_make_op_error_space(asoc, chunk, paylen); + retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail); if (!retval) goto nodata; - sctp_init_cause(retval, cause_code, paylen); + sctp_init_cause(retval, cause_code, paylen + reserve_tail); sctp_addto_chunk(retval, paylen, payload); + if (reserve_tail) + sctp_addto_param(retval, reserve_tail, NULL); nodata: return retval; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 8ee24c9dc7e..16a603527df 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1720,7 +1720,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_COOKIE_IN_SHUTDOWN, - NULL, 0); + NULL, 0, 0); if (err) sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err)); @@ -3977,7 +3977,7 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep, err_chunk = sctp_make_op_error(asoc, chunk, SCTP_ERROR_UNSUP_HMAC, &auth_hdr->hmac_id, - sizeof(__u16)); + sizeof(__u16), 0); if (err_chunk) { sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err_chunk)); @@ -4069,7 +4069,8 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep, hdr = unk_chunk->chunk_hdr; err_chunk = sctp_make_op_error(asoc, unk_chunk, SCTP_ERROR_UNKNOWN_CHUNK, hdr, - WORD_ROUND(ntohs(hdr->length))); + WORD_ROUND(ntohs(hdr->length)), + 0); if (err_chunk) { sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err_chunk)); @@ -4088,7 +4089,8 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep, hdr = unk_chunk->chunk_hdr; err_chunk = sctp_make_op_error(asoc, unk_chunk, SCTP_ERROR_UNKNOWN_CHUNK, hdr, - WORD_ROUND(ntohs(hdr->length))); + WORD_ROUND(ntohs(hdr->length)), + 0); if (err_chunk) { sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err_chunk)); @@ -6052,7 +6054,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, &data_hdr->stream, - sizeof(data_hdr->stream)); + sizeof(data_hdr->stream), + sizeof(u16)); if (err) sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err)); -- cgit v1.2.3 From e0e9db178a5ba4dbb5f16f958f1affbdc63d2cc4 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 23 Nov 2009 15:53:57 -0500 Subject: sctp: Select a working primary during sctp_connectx() When sctp_connectx() is used, we pick the first address as primary, even though it may not have worked. This results in excessive retransmits and poor performance. We should select the address that the association was established with. Reported-by: Thomas Dreibholz Signed-off-by: Vlad Yasevich --- net/sctp/associola.c | 6 ++++++ net/sctp/sm_sideeffect.c | 2 ++ 2 files changed, 8 insertions(+) (limited to 'net') diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 7eed77a39d0..8e755ebff3b 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -512,7 +512,13 @@ void sctp_assoc_set_primary(struct sctp_association *asoc, * to this destination address earlier. The sender MUST set * CYCLING_CHANGEOVER to indicate that this switch is a * double switch to the same destination address. + * + * Really, only bother is we have data queued or outstanding on + * the association. */ + if (!asoc->outqueue.outstanding_bytes && !asoc->outqueue.out_qlen) + return; + if (transport->cacc.changeover_active) transport->cacc.cycling_changeover = changeover; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 8674d491955..eda4fe783be 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1418,6 +1418,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, asoc->init_last_sent_to = t; chunk->transport = t; t->init_sent_count++; + /* Set the new transport as primary */ + sctp_assoc_set_primary(asoc, t); break; case SCTP_CMD_INIT_RESTART: -- cgit v1.2.3 From 90f2f5318b3a5b0898fef0fec9b91376c7de7a2c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 23 Nov 2009 15:53:57 -0500 Subject: sctp: Update SWS avaoidance receiver side algorithm We currently send window update SACKs every time we free up 1 PMTU worth of data. That a lot more SACKs then necessary. Instead, we'll now send back the actuall window every time we send a sack, and do window-update SACKs when a fraction of the receive buffer has been opened. The fraction is controlled with a sysctl. Signed-off-by: Vlad Yasevich --- include/net/sctp/constants.h | 4 ++++ include/net/sctp/structs.h | 6 ++++++ net/sctp/associola.c | 5 +++-- net/sctp/protocol.c | 3 +++ net/sctp/sm_sideeffect.c | 3 +-- net/sctp/sysctl.c | 13 +++++++++++++ 6 files changed, 30 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 58f714a3b67..63908840eef 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -308,6 +308,10 @@ enum { SCTP_MAX_GABS = 16 }; #define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */ #define SCTP_DEFAULT_MAXWINDOW 65535 /* default rwnd size */ +#define SCTP_DEFAULT_RWND_SHIFT 4 /* by default, update on 1/16 of + * rcvbuf, which is 1/8 of initial + * window + */ #define SCTP_DEFAULT_MAXSEGMENT 1500 /* MTU size, this is the limit * to which we will raise the P-MTU. */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index cd2e18778f8..90876b65777 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -231,6 +231,11 @@ extern struct sctp_globals { /* Flag to indicate whether computing and verifying checksum * is disabled. */ int checksum_disable; + + /* Threshold for rwnd update SACKS. Receive buffer shifted this many + * bits is an indicator of when to send and window update SACK. + */ + int rwnd_update_shift; } sctp_globals; #define sctp_rto_initial (sctp_globals.rto_initial) @@ -267,6 +272,7 @@ extern struct sctp_globals { #define sctp_prsctp_enable (sctp_globals.prsctp_enable) #define sctp_auth_enable (sctp_globals.auth_enable) #define sctp_checksum_disable (sctp_globals.checksum_disable) +#define sctp_rwnd_upd_shift (sctp_globals.rwnd_update_shift) /* SCTP Socket type: UDP or TCP style. */ typedef enum { diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 8e755ebff3b..37e982510be 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1383,8 +1383,9 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc) case SCTP_STATE_SHUTDOWN_RECEIVED: case SCTP_STATE_SHUTDOWN_SENT: if ((asoc->rwnd > asoc->a_rwnd) && - ((asoc->rwnd - asoc->a_rwnd) >= - min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pathmtu))) + ((asoc->rwnd - asoc->a_rwnd) >= max_t(__u32, + (asoc->base.sk->sk_rcvbuf >> sctp_rwnd_upd_shift), + asoc->pathmtu))) return 1; break; default: diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 08ef203d36a..a3c8988758b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1258,6 +1258,9 @@ SCTP_STATIC __init int sctp_init(void) /* Set SCOPE policy to enabled */ sctp_scope_policy = SCTP_SCOPE_POLICY_ENABLE; + /* Set the default rwnd update threshold */ + sctp_rwnd_upd_shift = SCTP_DEFAULT_RWND_SHIFT; + sctp_sysctl_register(); INIT_LIST_HEAD(&sctp_address_families); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index eda4fe783be..8ae67098e09 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -217,8 +217,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); } else { - if (asoc->a_rwnd > asoc->rwnd) - asoc->a_rwnd = asoc->rwnd; + asoc->a_rwnd = asoc->rwnd; sack = sctp_make_sack(asoc); if (!sack) goto nomem; diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index ab7151da120..ae03ded2bf1 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -52,6 +52,7 @@ static int int_max = INT_MAX; static int sack_timer_min = 1; static int sack_timer_max = 500; static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ +static int rwnd_scale_max = 16; extern int sysctl_sctp_mem[3]; extern int sysctl_sctp_rmem[3]; @@ -284,6 +285,18 @@ static ctl_table sctp_table[] = { .extra1 = &zero, .extra2 = &addr_scope_max, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "rwnd_update_shift", + .data = &sctp_rwnd_upd_shift, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &one, + .extra2 = &rwnd_scale_max, + }, + { .ctl_name = 0 } }; -- cgit v1.2.3 From 37051f73862d15862aecc08b887b2884137af327 Mon Sep 17 00:00:00 2001 From: Andrei Pelinescu-Onciul Date: Mon, 23 Nov 2009 15:53:57 -0500 Subject: sctp: allow setting path_maxrxt independent of SPP_PMTUD_ENABLE Since draft-ietf-tsvwg-sctpsocket-15.txt, setting the SPP_MTUD_ENABLE flag when changing pathmaxrxt via the SCTP_PEER_ADDR_PARAMS setsockopt is not required any longer. Signed-off-by: Andrei Pelinescu-Onciul Signed-off-by: Vlad Yasevich --- net/sctp/socket.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 66b1f02b17b..a4577a75c6c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2311,11 +2311,10 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, } } - /* Note that unless the spp_flag is set to SPP_PMTUD_ENABLE the value - * of this field is ignored. Note also that a value of zero - * indicates the current setting should be left unchanged. + /* Note that a value of zero indicates the current setting should be + left unchanged. */ - if ((params->spp_flags & SPP_PMTUD_ENABLE) && params->spp_pathmaxrxt) { + if (params->spp_pathmaxrxt) { if (trans) { trans->pathmaxrxt = params->spp_pathmaxrxt; } else if (asoc) { -- cgit v1.2.3 From a242b41dedfe0fd51ab1c906daa703c09b196744 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Mon, 23 Nov 2009 15:53:58 -0500 Subject: sctp: remove deprecated SCTP_GET_*_OLD stuffs SCTP_GET_*_OLD stuffs are schedlued to be removed. Cc: Vlad Yasevich Signed-off-by: WANG Cong Signed-off-by: Vlad Yasevich --- Documentation/feature-removal-schedule.txt | 12 -- include/net/sctp/user.h | 8 - net/sctp/socket.c | 325 ----------------------------- 3 files changed, 345 deletions(-) (limited to 'net') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index bc693fffabe..72ae06f73ac 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -302,18 +302,6 @@ Who: ocfs2-devel@oss.oracle.com --------------------------- -What: SCTP_GET_PEER_ADDRS_NUM_OLD, SCTP_GET_PEER_ADDRS_OLD, - SCTP_GET_LOCAL_ADDRS_NUM_OLD, SCTP_GET_LOCAL_ADDRS_OLD -When: June 2009 -Why: A newer version of the options have been introduced in 2005 that - removes the limitions of the old API. The sctp library has been - converted to use these new options at the same time. Any user - space app that directly uses the old options should convert to using - the new options. -Who: Vlad Yasevich - ---------------------------- - What: Ability for non root users to shm_get hugetlb pages based on mlock resource limits When: 2.6.31 diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 50b2431405f..fceab4d2413 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -131,14 +131,6 @@ enum sctp_optname { #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_PEELOFF, /* peel off association. */ #define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF - SCTP_GET_PEER_ADDRS_NUM_OLD, /* Get number of peer addresss. */ -#define SCTP_GET_PEER_ADDRS_NUM_OLD SCTP_GET_PEER_ADDRS_NUM_OLD - SCTP_GET_PEER_ADDRS_OLD, /* Get all peer addresss. */ -#define SCTP_GET_PEER_ADDRS_OLD SCTP_GET_PEER_ADDRS_OLD - SCTP_GET_LOCAL_ADDRS_NUM_OLD, /* Get number of local addresss. */ -#define SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_NUM_OLD - SCTP_GET_LOCAL_ADDRS_OLD, /* Get all local addresss. */ -#define SCTP_GET_LOCAL_ADDRS_OLD SCTP_GET_LOCAL_ADDRS_OLD SCTP_SOCKOPT_CONNECTX_OLD, /* CONNECTX old requests. */ #define SCTP_SOCKOPT_CONNECTX_OLD SCTP_SOCKOPT_CONNECTX_OLD SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a4577a75c6c..d2681a6bc6f 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4348,90 +4348,6 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval return 0; } -static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len, - char __user *optval, - int __user *optlen) -{ - sctp_assoc_t id; - struct sctp_association *asoc; - struct list_head *pos; - int cnt = 0; - - if (len < sizeof(sctp_assoc_t)) - return -EINVAL; - - if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) - return -EFAULT; - - printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_NUM_OLD " - "socket option deprecated\n"); - /* For UDP-style sockets, id specifies the association to query. */ - asoc = sctp_id2assoc(sk, id); - if (!asoc) - return -EINVAL; - - list_for_each(pos, &asoc->peer.transport_addr_list) { - cnt ++; - } - - return cnt; -} - -/* - * Old API for getting list of peer addresses. Does not work for 32-bit - * programs running on a 64-bit kernel - */ -static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len, - char __user *optval, - int __user *optlen) -{ - struct sctp_association *asoc; - int cnt = 0; - struct sctp_getaddrs_old getaddrs; - struct sctp_transport *from; - void __user *to; - union sctp_addr temp; - struct sctp_sock *sp = sctp_sk(sk); - int addrlen; - - if (len < sizeof(struct sctp_getaddrs_old)) - return -EINVAL; - - len = sizeof(struct sctp_getaddrs_old); - - if (copy_from_user(&getaddrs, optval, len)) - return -EFAULT; - - if (getaddrs.addr_num <= 0) return -EINVAL; - - printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_OLD " - "socket option deprecated\n"); - - /* For UDP-style sockets, id specifies the association to query. */ - asoc = sctp_id2assoc(sk, getaddrs.assoc_id); - if (!asoc) - return -EINVAL; - - to = (void __user *)getaddrs.addrs; - list_for_each_entry(from, &asoc->peer.transport_addr_list, - transports) { - memcpy(&temp, &from->ipaddr, sizeof(temp)); - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); - addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; - if (copy_to_user(to, &temp, addrlen)) - return -EFAULT; - to += addrlen ; - cnt ++; - if (cnt >= getaddrs.addr_num) break; - } - getaddrs.addr_num = cnt; - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &getaddrs, len)) - return -EFAULT; - - return 0; -} static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, char __user *optval, int __user *optlen) @@ -4484,125 +4400,6 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, return 0; } -static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, - char __user *optval, - int __user *optlen) -{ - sctp_assoc_t id; - struct sctp_bind_addr *bp; - struct sctp_association *asoc; - struct sctp_sockaddr_entry *addr; - int cnt = 0; - - if (len < sizeof(sctp_assoc_t)) - return -EINVAL; - - if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) - return -EFAULT; - - printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_NUM_OLD " - "socket option deprecated\n"); - - /* - * For UDP-style sockets, id specifies the association to query. - * If the id field is set to the value '0' then the locally bound - * addresses are returned without regard to any particular - * association. - */ - if (0 == id) { - bp = &sctp_sk(sk)->ep->base.bind_addr; - } else { - asoc = sctp_id2assoc(sk, id); - if (!asoc) - return -EINVAL; - bp = &asoc->base.bind_addr; - } - - /* If the endpoint is bound to 0.0.0.0 or ::0, count the valid - * addresses from the global local address list. - */ - if (sctp_list_single_entry(&bp->address_list)) { - addr = list_entry(bp->address_list.next, - struct sctp_sockaddr_entry, list); - if (sctp_is_any(sk, &addr->a)) { - rcu_read_lock(); - list_for_each_entry_rcu(addr, - &sctp_local_addr_list, list) { - if (!addr->valid) - continue; - - if ((PF_INET == sk->sk_family) && - (AF_INET6 == addr->a.sa.sa_family)) - continue; - - if ((PF_INET6 == sk->sk_family) && - inet_v6_ipv6only(sk) && - (AF_INET == addr->a.sa.sa_family)) - continue; - - cnt++; - } - rcu_read_unlock(); - } else { - cnt = 1; - } - goto done; - } - - /* Protection on the bound address list is not needed, - * since in the socket option context we hold the socket lock, - * so there is no way that the bound address list can change. - */ - list_for_each_entry(addr, &bp->address_list, list) { - cnt ++; - } -done: - return cnt; -} - -/* Helper function that copies local addresses to user and returns the number - * of addresses copied. - */ -static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, - int max_addrs, void *to, - int *bytes_copied) -{ - struct sctp_sockaddr_entry *addr; - union sctp_addr temp; - int cnt = 0; - int addrlen; - - rcu_read_lock(); - list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) { - if (!addr->valid) - continue; - - if ((PF_INET == sk->sk_family) && - (AF_INET6 == addr->a.sa.sa_family)) - continue; - if ((PF_INET6 == sk->sk_family) && - inet_v6_ipv6only(sk) && - (AF_INET == addr->a.sa.sa_family)) - continue; - memcpy(&temp, &addr->a, sizeof(temp)); - if (!temp.v4.sin_port) - temp.v4.sin_port = htons(port); - - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), - &temp); - addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; - memcpy(to, &temp, addrlen); - - to += addrlen; - *bytes_copied += addrlen; - cnt ++; - if (cnt >= max_addrs) break; - } - rcu_read_unlock(); - - return cnt; -} - static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, size_t space_left, int *bytes_copied) { @@ -4646,112 +4443,6 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, return cnt; } -/* Old API for getting list of local addresses. Does not work for 32-bit - * programs running on a 64-bit kernel - */ -static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, - char __user *optval, int __user *optlen) -{ - struct sctp_bind_addr *bp; - struct sctp_association *asoc; - int cnt = 0; - struct sctp_getaddrs_old getaddrs; - struct sctp_sockaddr_entry *addr; - void __user *to; - union sctp_addr temp; - struct sctp_sock *sp = sctp_sk(sk); - int addrlen; - int err = 0; - void *addrs; - void *buf; - int bytes_copied = 0; - - if (len < sizeof(struct sctp_getaddrs_old)) - return -EINVAL; - - len = sizeof(struct sctp_getaddrs_old); - if (copy_from_user(&getaddrs, optval, len)) - return -EFAULT; - - if (getaddrs.addr_num <= 0 || - getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr))) - return -EINVAL; - - printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_OLD " - "socket option deprecated\n"); - - /* - * For UDP-style sockets, id specifies the association to query. - * If the id field is set to the value '0' then the locally bound - * addresses are returned without regard to any particular - * association. - */ - if (0 == getaddrs.assoc_id) { - bp = &sctp_sk(sk)->ep->base.bind_addr; - } else { - asoc = sctp_id2assoc(sk, getaddrs.assoc_id); - if (!asoc) - return -EINVAL; - bp = &asoc->base.bind_addr; - } - - to = getaddrs.addrs; - - /* Allocate space for a local instance of packed array to hold all - * the data. We store addresses here first and then put write them - * to the user in one shot. - */ - addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num, - GFP_KERNEL); - if (!addrs) - return -ENOMEM; - - /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid - * addresses from the global local address list. - */ - if (sctp_list_single_entry(&bp->address_list)) { - addr = list_entry(bp->address_list.next, - struct sctp_sockaddr_entry, list); - if (sctp_is_any(sk, &addr->a)) { - cnt = sctp_copy_laddrs_old(sk, bp->port, - getaddrs.addr_num, - addrs, &bytes_copied); - goto copy_getaddrs; - } - } - - buf = addrs; - /* Protection on the bound address list is not needed since - * in the socket option context we hold a socket lock and - * thus the bound address list can't change. - */ - list_for_each_entry(addr, &bp->address_list, list) { - memcpy(&temp, &addr->a, sizeof(temp)); - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); - addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; - memcpy(buf, &temp, addrlen); - buf += addrlen; - bytes_copied += addrlen; - cnt ++; - if (cnt >= getaddrs.addr_num) break; - } - -copy_getaddrs: - /* copy the entire address list into the user provided space */ - if (copy_to_user(to, addrs, bytes_copied)) { - err = -EFAULT; - goto error; - } - - /* copy the leading structure back to user */ - getaddrs.addr_num = cnt; - if (copy_to_user(optval, &getaddrs, len)) - err = -EFAULT; - -error: - kfree(addrs); - return err; -} static int sctp_getsockopt_local_addrs(struct sock *sk, int len, char __user *optval, int __user *optlen) @@ -5602,22 +5293,6 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_INITMSG: retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); break; - case SCTP_GET_PEER_ADDRS_NUM_OLD: - retval = sctp_getsockopt_peer_addrs_num_old(sk, len, optval, - optlen); - break; - case SCTP_GET_LOCAL_ADDRS_NUM_OLD: - retval = sctp_getsockopt_local_addrs_num_old(sk, len, optval, - optlen); - break; - case SCTP_GET_PEER_ADDRS_OLD: - retval = sctp_getsockopt_peer_addrs_old(sk, len, optval, - optlen); - break; - case SCTP_GET_LOCAL_ADDRS_OLD: - retval = sctp_getsockopt_local_addrs_old(sk, len, optval, - optlen); - break; case SCTP_GET_PEER_ADDRS: retval = sctp_getsockopt_peer_addrs(sk, len, optval, optlen); -- cgit v1.2.3 From 245cba7e55929dc2b10b7d915bfba0168eeeed17 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 23 Nov 2009 15:53:58 -0500 Subject: sctp: Remove useless last_time_used variable The transport last_time_used variable is rather useless. It was only used when determining if CWND needs to be updated due to idle transport. However, idle transport detection was based on a Heartbeat timer and last_time_used was not incremented when sending Heartbeats. As a result the check for cwnd reduction was always true. We can get rid of the variable and just base our cwnd manipulation on the HB timer (like the code comment sais). We also have to call into the cwnd manipulation function regardless of whether HBs are enabled or not. That way we will detect idle transports if the user has disabled Heartbeats. Signed-off-by: Vlad Yasevich --- include/net/sctp/structs.h | 6 ------ net/sctp/output.c | 2 -- net/sctp/sm_statefuns.c | 5 +++-- net/sctp/transport.c | 7 ++----- 4 files changed, 5 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 90876b65777..ac794a6823e 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -950,12 +950,6 @@ struct sctp_transport { /* Source address. */ union sctp_addr saddr; - /* When was the last time(in jiffies) that a data packet was sent on - * this transport? This is used to adjust the cwnd when the transport - * becomes inactive. - */ - unsigned long last_time_used; - /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to * the destination address every heartbeat interval. */ diff --git a/net/sctp/output.c b/net/sctp/output.c index 5cbda8f1ddf..9e8e0ea844b 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -557,8 +557,6 @@ int sctp_packet_transmit(struct sctp_packet *packet) struct timer_list *timer; unsigned long timeout; - tp->last_time_used = jiffies; - /* Restart the AUTOCLOSE timer when sending data. */ if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) { timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 16a603527df..1ef9de9bbae 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -996,14 +996,15 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, sctp_sf_heartbeat(ep, asoc, type, arg, commands)) return SCTP_DISPOSITION_NOMEM; + /* Set transport error counter and association error counter * when sending heartbeat. */ - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_IDLE, - SCTP_TRANSPORT(transport)); sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_HB_SENT, SCTP_TRANSPORT(transport)); } + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_IDLE, + SCTP_TRANSPORT(transport)); sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMER_UPDATE, SCTP_TRANSPORT(transport)); diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 3b141bb32fa..2df29cbdaf5 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -83,7 +83,6 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, peer->fast_recovery = 0; peer->last_time_heard = jiffies; - peer->last_time_used = jiffies; peer->last_time_ecne_reduced = jiffies; peer->init_sent_count = 0; @@ -565,10 +564,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, * to be done every RTO interval, we do it every hearbeat * interval. */ - if (time_after(jiffies, transport->last_time_used + - transport->rto)) - transport->cwnd = max(transport->cwnd/2, - 4*transport->asoc->pathmtu); + transport->cwnd = max(transport->cwnd/2, + 4*transport->asoc->pathmtu); break; } -- cgit v1.2.3 From 46d5a808558181e03a4760d2188cc9879445738a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 23 Nov 2009 15:54:00 -0500 Subject: sctp: Update max.burst implementation Current implementation of max.burst ends up limiting new data during cwnd decay period. The decay is happening becuase the connection is idle and we are allowed to fill the congestion window. The point of max.burst is to limit micro-bursts in response to large acks. This still happens, as max.burst is still applied to each transmit opportunity. It will also apply if a very large send is made (greater then allowed by burst). Tested-by: Florian Niederbacher Signed-off-by: Vlad Yasevich --- include/net/sctp/structs.h | 4 ++++ net/sctp/associola.c | 1 + net/sctp/output.c | 23 ----------------------- net/sctp/outqueue.c | 15 +++++++++++++++ net/sctp/transport.c | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ac794a6823e..bc3f8d879c5 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -942,6 +942,8 @@ struct sctp_transport { /* Data that has been sent, but not acknowledged. */ __u32 flight_size; + __u32 burst_limited; /* Holds old cwnd when max.burst is applied */ + /* TSN marking the fast recovery exit point */ __u32 fast_recovery_exit; @@ -1070,6 +1072,8 @@ void sctp_transport_put(struct sctp_transport *); void sctp_transport_update_rto(struct sctp_transport *, __u32); void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32); void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t); +void sctp_transport_burst_limited(struct sctp_transport *); +void sctp_transport_burst_reset(struct sctp_transport *); unsigned long sctp_transport_timeout(struct sctp_transport *); void sctp_transport_reset(struct sctp_transport *); void sctp_transport_update_pmtu(struct sctp_transport *, u32); diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 37e982510be..880dae2ca87 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -738,6 +738,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, peer->partial_bytes_acked = 0; peer->flight_size = 0; + peer->burst_limited = 0; /* Set the transport's RTO.initial value */ peer->rto = asoc->rto_initial; diff --git a/net/sctp/output.c b/net/sctp/output.c index 9e8e0ea844b..b210d2077e2 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -615,7 +615,6 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, sctp_xmit_t retval = SCTP_XMIT_OK; size_t datasize, rwnd, inflight, flight_size; struct sctp_transport *transport = packet->transport; - __u32 max_burst_bytes; struct sctp_association *asoc = transport->asoc; struct sctp_outq *q = &asoc->outqueue; @@ -648,28 +647,6 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, } } - /* sctpimpguide-05 2.14.2 - * D) When the time comes for the sender to - * transmit new DATA chunks, the protocol parameter Max.Burst MUST - * first be applied to limit how many new DATA chunks may be sent. - * The limit is applied by adjusting cwnd as follows: - * if ((flightsize + Max.Burst * MTU) < cwnd) - * cwnd = flightsize + Max.Burst * MTU - */ - max_burst_bytes = asoc->max_burst * asoc->pathmtu; - if ((flight_size + max_burst_bytes) < transport->cwnd) { - transport->cwnd = flight_size + max_burst_bytes; - SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " - "transport: %p, cwnd: %d, " - "ssthresh: %d, flight_size: %d, " - "pba: %d\n", - __func__, transport, - transport->cwnd, - transport->ssthresh, - transport->flight_size, - transport->partial_bytes_acked); - } - /* RFC 2960 6.1 Transmission of DATA Chunks * * B) At any given time, the sender MUST NOT transmit new data diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 5732661c87d..2f2377369e2 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -931,6 +931,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) goto sctp_flush_out; } + /* Apply Max.Burst limitation to the current transport in + * case it will be used for new data. We are going to + * rest it before we return, but we want to apply the limit + * to the currently queued data. + */ + if (transport) + sctp_transport_burst_limited(transport); + /* Finally, transmit new packets. */ while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* RFC 2960 6.5 Every DATA chunk MUST carry a valid @@ -976,6 +984,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) packet = &transport->packet; sctp_packet_config(packet, vtag, asoc->peer.ecn_capable); + /* We've switched transports, so apply the + * Burst limit to the new transport. + */ + sctp_transport_burst_limited(transport); } SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ", @@ -1070,6 +1082,9 @@ sctp_flush_out: packet = &t->packet; if (!sctp_packet_empty(packet)) error = sctp_packet_transmit(packet); + + /* Clear the burst limited state, if any */ + sctp_transport_burst_reset(t); } return error; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 2df29cbdaf5..9a6cb22d129 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -576,6 +576,43 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, transport->cwnd, transport->ssthresh); } +/* Apply Max.Burst limit to the congestion window: + * sctpimpguide-05 2.14.2 + * D) When the time comes for the sender to + * transmit new DATA chunks, the protocol parameter Max.Burst MUST + * first be applied to limit how many new DATA chunks may be sent. + * The limit is applied by adjusting cwnd as follows: + * if ((flightsize+ Max.Burst * MTU) < cwnd) + * cwnd = flightsize + Max.Burst * MTU + */ + +void sctp_transport_burst_limited(struct sctp_transport *t) +{ + struct sctp_association *asoc = t->asoc; + u32 old_cwnd = t->cwnd; + u32 max_burst_bytes; + + if (t->burst_limited) + return; + + max_burst_bytes = t->flight_size + (asoc->max_burst * asoc->pathmtu); + if (max_burst_bytes < old_cwnd) { + t->cwnd = max_burst_bytes; + t->burst_limited = old_cwnd; + } +} + +/* Restore the old cwnd congestion window, after the burst had it's + * desired effect. + */ +void sctp_transport_burst_reset(struct sctp_transport *t) +{ + if (t->burst_limited) { + t->cwnd = t->burst_limited; + t->burst_limited = 0; + } +} + /* What is the next timeout value for this transport? */ unsigned long sctp_transport_timeout(struct sctp_transport *t) { @@ -598,6 +635,7 @@ void sctp_transport_reset(struct sctp_transport *t) * (see Section 6.2.1) */ t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380)); + t->burst_limited = 0; t->ssthresh = asoc->peer.i.a_rwnd; t->last_rto = t->rto = asoc->rto_initial; t->rtt = 0; -- cgit v1.2.3 From d8dd15781dd621c5ceab79083f4c5112787863f5 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 23 Nov 2009 15:54:00 -0500 Subject: sctp: Fix mis-ordering of user space data when multihoming in use Recently had a bug reported to me, in which the user was sending packets with a payload containing a sequence number. The packets were getting delivered in order according the chunk TSN values, but the sequence values in the payload were arriving out of order. At first I thought it must be an application error, but we eventually found it to be a problem on the transmit side in the sctp stack. The conditions for the error are that multihoming must be in use, and it helps if each transport has a different pmtu. The problem occurs in sctp_outq_flush. Basically we dequeue packets from the data queue, and attempt to append them to the orrered packet for a given transport. After we append a data chunk we add the trasport to the end of a list of transports to have their packets sent at the end of sctp_outq_flush. The problem occurs when a data chunks fills up a offered packet on a transport. The function that does the appending (sctp_packet_transmit_chunk), will try to call sctp_packet_transmit on the full packet, and then append the chunk to a new packet. This call to sctp_packet_transmit, sends that packet ahead of the others that may be queued in the transport_list in sctp_outq_flush. The result is that frames that were sent in one order from the user space sending application get re-ordered prior to tsn assignment in sctp_packet_transmit, resulting in mis-sequencing of data payloads, even though tsn ordering is correct. The fix is to change where we assign a tsn. By doing this earlier, we are then free to place chunks in packets, whatever way we see fit and the protocol will make sure to do all the appropriate re-ordering on receive as is needed. Signed-off-by: Neil Horman Reported-by: William Reich Signed-off-by: Vlad Yasevich --- net/sctp/output.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/sctp/output.c b/net/sctp/output.c index b210d2077e2..7c558936343 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -429,23 +429,22 @@ int sctp_packet_transmit(struct sctp_packet *packet) list_del_init(&chunk->list); if (sctp_chunk_is_data(chunk)) { - if (!chunk->has_tsn) { - sctp_chunk_assign_ssn(chunk); - sctp_chunk_assign_tsn(chunk); - - /* 6.3.1 C4) When data is in flight and when allowed - * by rule C5, a new RTT measurement MUST be made each - * round trip. Furthermore, new RTT measurements - * SHOULD be made no more than once per round-trip - * for a given destination transport address. - */ + if (!chunk->resent) { + + /* 6.3.1 C4) When data is in flight and when allowed + * by rule C5, a new RTT measurement MUST be made each + * round trip. Furthermore, new RTT measurements + * SHOULD be made no more than once per round-trip + * for a given destination transport address. + */ if (!tp->rto_pending) { chunk->rtt_in_progress = 1; tp->rto_pending = 1; } - } else - chunk->resent = 1; + } + + chunk->resent = 1; has_data = 1; } @@ -722,6 +721,8 @@ static void sctp_packet_append_data(struct sctp_packet *packet, /* Has been accepted for transmission. */ if (!asoc->peer.prsctp_capable) chunk->msg->can_abandon = 0; + sctp_chunk_assign_tsn(chunk); + sctp_chunk_assign_ssn(chunk); } static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, -- cgit v1.2.3 From f6778aab6ccc4b510b4dcfa770d9949b696b4545 Mon Sep 17 00:00:00 2001 From: Andrei Pelinescu-Onciul Date: Mon, 23 Nov 2009 15:54:01 -0500 Subject: sctp: limit maximum autoclose setsockopt value To avoid overflowing the maximum timer interval when transforming the autoclose interval from seconds to jiffies, limit the maximum autoclose value to MAX_SCHEDULE_TIMEOUT/HZ. Signed-off-by: Andrei Pelinescu-Onciul Signed-off-by: Vlad Yasevich --- net/sctp/socket.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d2681a6bc6f..71513b3926a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2086,6 +2086,9 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, return -EINVAL; if (copy_from_user(&sp->autoclose, optval, optlen)) return -EFAULT; + /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */ + if (sp->autoclose > (MAX_SCHEDULE_TIMEOUT / HZ) ) + sp->autoclose = MAX_SCHEDULE_TIMEOUT / HZ ; return 0; } -- cgit v1.2.3 From da85b7396f3b6cb3fea7d77091498bfa1051ef7c Mon Sep 17 00:00:00 2001 From: Andrei Pelinescu-Onciul Date: Mon, 23 Nov 2009 15:54:01 -0500 Subject: sctp: fix integer overflow when setting the autoclose timer When setting the autoclose timeout in jiffies there is a possible integer overflow if the value in seconds is very large (e.g. for 2^22 s with HZ=1024). The problem appears even on 64-bit due to the integer promotion rules. The fix is just a cast to unsigned long. Signed-off-by: Andrei Pelinescu-Onciul Signed-off-by: Vlad Yasevich --- net/sctp/associola.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 880dae2ca87..6e96f83570c 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -167,7 +167,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = - sp->autoclose * HZ; + (unsigned long)sp->autoclose * HZ; /* Initilizes the timers */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) -- cgit v1.2.3 From 4814326b59db0cfd18ac652626d955ad3f57fb0f Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 23 Nov 2009 15:54:01 -0500 Subject: sctp: prevent too-fast association id reuse We use the idr subsystem and always ask for an id at or above 1. This results in a id reuse when one association is terminated while another is created. To prevent re-use, we keep track of the last id returned and ask for that id + 1 as a base for each query. We let the idr spin lock protect this base id as well. Signed-off-by: Vlad Yasevich --- net/sctp/associola.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 6e96f83570c..df5abbff63e 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -63,6 +63,12 @@ static void sctp_assoc_bh_rcv(struct work_struct *work); static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc); +/* Keep track of the new idr low so that we don't re-use association id + * numbers too fast. It is protected by they idr spin lock is in the + * range of 1 - INT_MAX. + */ +static u32 idr_low = 1; + /* 1st Level Abstractions. */ @@ -1553,7 +1559,12 @@ retry: spin_lock_bh(&sctp_assocs_id_lock); error = idr_get_new_above(&sctp_assocs_id, (void *)asoc, - 1, &assoc_id); + idr_low, &assoc_id); + if (!error) { + idr_low = assoc_id + 1; + if (idr_low == INT_MAX) + idr_low = 1; + } spin_unlock_bh(&sctp_assocs_id_lock); if (error == -EAGAIN) goto retry; -- cgit v1.2.3 From 98e3ac99e25601c3fb83dc91367d76f864496847 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 22:42:16 +0100 Subject: mac80211: remove dead struct member ieee80211_local.wstats is a remnant from the days when we still had to worry about wireless extensions in mac80211 -- it can be removed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f13d76c9b57..04093e84ebd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -579,7 +579,6 @@ struct ieee80211_local { /* number of interfaces with corresponding FIF_ flags */ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; unsigned int filter_flags; /* FIF_* */ - struct iw_statistics wstats; /* protects the aggregated multicast list and filter calls */ spinlock_t filter_lock; -- cgit v1.2.3 From 3305443c968b98902199bea0abbd9443c6a2bb8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Nov 2009 10:09:14 +0100 Subject: mac80211: fix rcu locking Add a missing rcu_read_unlock() before jumping out of the ieee80211_change_station() function in the error case. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c484a882140..93ee1fd5c08 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -823,8 +823,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, } if (params->vlan->ieee80211_ptr->use_4addr) { - if (vlansdata->u.vlan.sta) + if (vlansdata->u.vlan.sta) { + rcu_read_unlock(); return -EBUSY; + } rcu_assign_pointer(vlansdata->u.vlan.sta, sta); } -- cgit v1.2.3 From 841507f5c1a5d2f196afb12e95eb11914f029832 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 22 Nov 2009 13:47:58 +0530 Subject: mac80211: Fix missing kernel-doc notation Fix the following htmldocs warnings: Warning(net/mac80211/sta_info.h:322): No description found for parameter 'drv_unblock_wk' Warning(net/mac80211/sta_info.h:322): No description found for parameter 'drv_unblock_wk' Signed-off-by: Jaswinder Singh Rajput Cc: Johannes Berg Cc: John W. Linville Cc: Randy Dunlap Cc: David Miller Signed-off-by: John W. Linville --- net/mac80211/sta_info.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4c84c2205e8..b4810f6aa94 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -185,6 +185,7 @@ struct sta_ampdu_mlme { * @lock: used for locking all fields that require locking, see comments * in the header file. * @flaglock: spinlock for flags accesses + * @drv_unblock_wk: used for driver PS unblocking * @listen_interval: listen interval of this station, when we're acting as AP * @pin_status: used internally for pinning a STA struct into memory * @flags: STA flags, see &enum ieee80211_sta_info_flags @@ -225,7 +226,6 @@ struct sta_ampdu_mlme { * @debugfs: debug filesystem info * @sta: station information we share with the driver * @dead: set to true when sta is unlinked - * @drv_unblock_wk used for driver PS unblocking */ struct sta_info { /* General information, mostly static */ -- cgit v1.2.3 From 3666ed1c4837fd6906da0224c5373d7a2186a193 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 23 Nov 2009 23:17:06 +0100 Subject: netfilter: net/ipv[46]/netfilter: Move && and || to end of previous line Compile tested only. Signed-off-by: Joe Perches Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/arp_tables.c | 22 ++++++------ net/ipv4/netfilter/ip_tables.c | 46 ++++++++++++------------- net/ipv4/netfilter/ipt_CLUSTERIP.c | 20 +++++------ net/ipv4/netfilter/ipt_ECN.c | 8 ++--- net/ipv4/netfilter/ipt_LOG.c | 22 ++++++------ net/ipv4/netfilter/ipt_MASQUERADE.c | 4 +-- net/ipv4/netfilter/ipt_REJECT.c | 4 +-- net/ipv4/netfilter/ipt_ULOG.c | 6 ++-- net/ipv4/netfilter/ipt_ecn.c | 4 +-- net/ipv4/netfilter/iptable_mangle.c | 4 +-- net/ipv4/netfilter/iptable_security.c | 4 +-- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 28 +++++++-------- net/ipv4/netfilter/nf_nat_standalone.c | 10 +++--- net/ipv6/netfilter/ip6_tables.c | 42 +++++++++++------------ net/ipv6/netfilter/ip6t_LOG.c | 4 +-- net/ipv6/netfilter/ip6t_REJECT.c | 4 +-- net/ipv6/netfilter/ip6t_ah.c | 19 +++++------ net/ipv6/netfilter/ip6t_frag.c | 47 ++++++++++++-------------- net/ipv6/netfilter/ip6t_rt.c | 9 ++--- net/ipv6/netfilter/ip6table_filter.c | 4 +-- net/ipv6/netfilter/ip6table_mangle.c | 14 ++++---- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 12 +++---- 22 files changed, 163 insertions(+), 174 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 27774c99d88..06632762ba5 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -384,11 +384,11 @@ static int mark_source_chains(struct xt_table_info *newinfo, |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS)); /* Unconditional return/END. */ - if ((e->target_offset == sizeof(struct arpt_entry) - && (strcmp(t->target.u.user.name, - ARPT_STANDARD_TARGET) == 0) - && t->verdict < 0 - && unconditional(&e->arp)) || visited) { + if ((e->target_offset == sizeof(struct arpt_entry) && + (strcmp(t->target.u.user.name, + ARPT_STANDARD_TARGET) == 0) && + t->verdict < 0 && unconditional(&e->arp)) || + visited) { unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, @@ -427,8 +427,8 @@ static int mark_source_chains(struct xt_table_info *newinfo, int newpos = t->verdict; if (strcmp(t->target.u.user.name, - ARPT_STANDARD_TARGET) == 0 - && newpos >= 0) { + ARPT_STANDARD_TARGET) == 0 && + newpos >= 0) { if (newpos > newinfo->size - sizeof(struct arpt_entry)) { duprintf("mark_source_chains: " @@ -559,8 +559,8 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, { unsigned int h; - if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 - || (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { + if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || + (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { duprintf("Bad offset %p\n", e); return -EINVAL; } @@ -1251,8 +1251,8 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, int ret, off, h; duprintf("check_compat_entry_size_and_hooks %p\n", e); - if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 - || (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) { + if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 || + (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) { duprintf("Bad offset %p, limit = %p\n", e, limit); return -EINVAL; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index cde755d5eea..572330a552e 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -89,9 +89,9 @@ ip_packet_match(const struct iphdr *ip, #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, - IPT_INV_SRCIP) - || FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, - IPT_INV_DSTIP)) { + IPT_INV_SRCIP) || + FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, + IPT_INV_DSTIP)) { dprintf("Source or dest mismatch.\n"); dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n", @@ -122,8 +122,8 @@ ip_packet_match(const struct iphdr *ip, } /* Check specific protocol */ - if (ipinfo->proto - && FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) { + if (ipinfo->proto && + FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) { dprintf("Packet protocol %hi does not match %hi.%s\n", ip->protocol, ipinfo->proto, ipinfo->invflags&IPT_INV_PROTO ? " (INV)":""); @@ -246,11 +246,11 @@ get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, } else if (s == e) { (*rulenum)++; - if (s->target_offset == sizeof(struct ipt_entry) - && strcmp(t->target.u.kernel.target->name, - IPT_STANDARD_TARGET) == 0 - && t->verdict < 0 - && unconditional(&s->ip)) { + if (s->target_offset == sizeof(struct ipt_entry) && + strcmp(t->target.u.kernel.target->name, + IPT_STANDARD_TARGET) == 0 && + t->verdict < 0 && + unconditional(&s->ip)) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname ? comments[NF_IP_TRACE_COMMENT_POLICY] @@ -388,8 +388,8 @@ ipt_do_table(struct sk_buff *skb, back = get_entry(table_base, back->comefrom); continue; } - if (table_base + v != ipt_next_entry(e) - && !(e->ip.flags & IPT_F_GOTO)) { + if (table_base + v != ipt_next_entry(e) && + !(e->ip.flags & IPT_F_GOTO)) { /* Save old back ptr in next entry */ struct ipt_entry *next = ipt_next_entry(e); next->comefrom = (void *)back - table_base; @@ -473,11 +473,11 @@ mark_source_chains(struct xt_table_info *newinfo, e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); /* Unconditional return/END. */ - if ((e->target_offset == sizeof(struct ipt_entry) - && (strcmp(t->target.u.user.name, - IPT_STANDARD_TARGET) == 0) - && t->verdict < 0 - && unconditional(&e->ip)) || visited) { + if ((e->target_offset == sizeof(struct ipt_entry) && + (strcmp(t->target.u.user.name, + IPT_STANDARD_TARGET) == 0) && + t->verdict < 0 && unconditional(&e->ip)) || + visited) { unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, @@ -524,8 +524,8 @@ mark_source_chains(struct xt_table_info *newinfo, int newpos = t->verdict; if (strcmp(t->target.u.user.name, - IPT_STANDARD_TARGET) == 0 - && newpos >= 0) { + IPT_STANDARD_TARGET) == 0 && + newpos >= 0) { if (newpos > newinfo->size - sizeof(struct ipt_entry)) { duprintf("mark_source_chains: " @@ -735,8 +735,8 @@ check_entry_size_and_hooks(struct ipt_entry *e, { unsigned int h; - if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 - || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { + if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 || + (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { duprintf("Bad offset %p\n", e); return -EINVAL; } @@ -1548,8 +1548,8 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, int ret, off, h; duprintf("check_compat_entry_size_and_hooks %p\n", e); - if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 - || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) { + if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 || + (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) { duprintf("Bad offset %p, limit = %p\n", e, limit); return -EINVAL; } diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 2e4f98b8552..40ca2d240ab 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -303,9 +303,9 @@ clusterip_tg(struct sk_buff *skb, const struct xt_target_param *par) /* special case: ICMP error handling. conntrack distinguishes between * error messages (RELATED) and information requests (see below) */ - if (ip_hdr(skb)->protocol == IPPROTO_ICMP - && (ctinfo == IP_CT_RELATED - || ctinfo == IP_CT_RELATED+IP_CT_IS_REPLY)) + if (ip_hdr(skb)->protocol == IPPROTO_ICMP && + (ctinfo == IP_CT_RELATED || + ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)) return XT_CONTINUE; /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO, @@ -362,8 +362,8 @@ static bool clusterip_tg_check(const struct xt_tgchk_param *par) return false; } - if (e->ip.dmsk.s_addr != htonl(0xffffffff) - || e->ip.dst.s_addr == 0) { + if (e->ip.dmsk.s_addr != htonl(0xffffffff) || + e->ip.dst.s_addr == 0) { printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n"); return false; } @@ -495,14 +495,14 @@ arp_mangle(unsigned int hook, struct clusterip_config *c; /* we don't care about non-ethernet and non-ipv4 ARP */ - if (arp->ar_hrd != htons(ARPHRD_ETHER) - || arp->ar_pro != htons(ETH_P_IP) - || arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN) + if (arp->ar_hrd != htons(ARPHRD_ETHER) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN) return NF_ACCEPT; /* we only want to mangle arp requests and replies */ - if (arp->ar_op != htons(ARPOP_REPLY) - && arp->ar_op != htons(ARPOP_REQUEST)) + if (arp->ar_op != htons(ARPOP_REPLY) && + arp->ar_op != htons(ARPOP_REQUEST)) return NF_ACCEPT; payload = (void *)(arp+1); diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index f7e2fa0974d..549e206cdd4 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -85,8 +85,8 @@ ecn_tg(struct sk_buff *skb, const struct xt_target_param *par) if (!set_ect_ip(skb, einfo)) return NF_DROP; - if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR) - && ip_hdr(skb)->protocol == IPPROTO_TCP) + if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR) && + ip_hdr(skb)->protocol == IPPROTO_TCP) if (!set_ect_tcp(skb, einfo)) return NF_DROP; @@ -108,8 +108,8 @@ static bool ecn_tg_check(const struct xt_tgchk_param *par) einfo->ip_ect); return false; } - if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) - && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) { + if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) && + (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) { printk(KERN_WARNING "ECN: cannot use TCP operations on a " "non-tcp rule\n"); return false; diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index acc44c69eb6..ee128efa1c8 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -74,8 +74,8 @@ static void dump_packet(const struct nf_loginfo *info, if (ntohs(ih->frag_off) & IP_OFFSET) printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); - if ((logflags & IPT_LOG_IPOPT) - && ih->ihl * 4 > sizeof(struct iphdr)) { + if ((logflags & IPT_LOG_IPOPT) && + ih->ihl * 4 > sizeof(struct iphdr)) { const unsigned char *op; unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; unsigned int i, optsize; @@ -146,8 +146,8 @@ static void dump_packet(const struct nf_loginfo *info, /* Max length: 11 "URGP=65535 " */ printk("URGP=%u ", ntohs(th->urg_ptr)); - if ((logflags & IPT_LOG_TCPOPT) - && th->doff * 4 > sizeof(struct tcphdr)) { + if ((logflags & IPT_LOG_TCPOPT) && + th->doff * 4 > sizeof(struct tcphdr)) { unsigned char _opt[4 * 15 - sizeof(struct tcphdr)]; const unsigned char *op; unsigned int i, optsize; @@ -238,9 +238,9 @@ static void dump_packet(const struct nf_loginfo *info, printk("TYPE=%u CODE=%u ", ich->type, ich->code); /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - if (ich->type <= NR_ICMP_TYPES - && required_len[ich->type] - && skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { + if (ich->type <= NR_ICMP_TYPES && + required_len[ich->type] && + skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; @@ -276,8 +276,8 @@ static void dump_packet(const struct nf_loginfo *info, } /* Max length: 10 "MTU=65535 " */ - if (ich->type == ICMP_DEST_UNREACH - && ich->code == ICMP_FRAG_NEEDED) + if (ich->type == ICMP_DEST_UNREACH && + ich->code == ICMP_FRAG_NEEDED) printk("MTU=%u ", ntohs(ich->un.frag.mtu)); } break; @@ -407,8 +407,8 @@ ipt_log_packet(u_int8_t pf, if (in && !out) { /* MAC logging for input chain only. */ printk("MAC="); - if (skb->dev && skb->dev->hard_header_len - && skb->mac_header != skb->network_header) { + if (skb->dev && skb->dev->hard_header_len && + skb->mac_header != skb->network_header) { int i; const unsigned char *p = skb_mac_header(skb); for (i = 0; i < skb->dev->hard_header_len; i++,p++) diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index dada0863946..650b54042b0 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -59,8 +59,8 @@ masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par) ct = nf_ct_get(skb, &ctinfo); nat = nfct_nat(ct); - NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED - || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || + ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); /* Source address is 0.0.0.0 - locally generated packet that is * probably not supposed to be masqueraded. diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index c93ae44bff2..5113b8f1a37 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -184,8 +184,8 @@ static bool reject_tg_check(const struct xt_tgchk_param *par) return false; } else if (rejinfo->with == IPT_TCP_RESET) { /* Must specify that it's a TCP packet */ - if (e->ip.proto != IPPROTO_TCP - || (e->ip.invflags & XT_INV_PROTO)) { + if (e->ip.proto != IPPROTO_TCP || + (e->ip.invflags & XT_INV_PROTO)) { printk("ipt_REJECT: TCP_RESET invalid for non-tcp\n"); return false; } diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index d32cc4bb328..399061c3fd7 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -226,9 +226,9 @@ static void ipt_ulog_packet(unsigned int hooknum, else *(pm->prefix) = '\0'; - if (in && in->hard_header_len > 0 - && skb->mac_header != skb->network_header - && in->hard_header_len <= ULOG_MAC_LEN) { + if (in && in->hard_header_len > 0 && + skb->mac_header != skb->network_header && + in->hard_header_len <= ULOG_MAC_LEN) { memcpy(pm->mac, skb_mac_header(skb), in->hard_header_len); pm->mac_len = in->hard_header_len; } else diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c index 6289b64144c..2a1e56b7190 100644 --- a/net/ipv4/netfilter/ipt_ecn.c +++ b/net/ipv4/netfilter/ipt_ecn.c @@ -96,8 +96,8 @@ static bool ecn_mt_check(const struct xt_mtchk_param *par) if (info->invert & IPT_ECN_OP_MATCH_MASK) return false; - if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) - && ip->proto != IPPROTO_TCP) { + if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) && + ip->proto != IPPROTO_TCP) { printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for" " non-tcp packets\n"); return false; diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 036047f9b0f..fae78c3076c 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -130,8 +130,8 @@ ipt_local_hook(unsigned int hook, u_int32_t mark; /* root is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) - || ip_hdrlen(skb) < sizeof(struct iphdr)) + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; /* Save things which could affect route */ diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index 99eb76c65d2..3bd3d6388da 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -94,8 +94,8 @@ ipt_local_out_hook(unsigned int hook, int (*okfn)(struct sk_buff *)) { /* Somebody is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) - || ip_hdrlen(skb) < sizeof(struct iphdr)) + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; return ipt_do_table(skb, hook, in, out, dev_net(out)->ipv4.iptable_security); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index d71ba767734..e3dd93623df 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -54,8 +54,8 @@ static const u_int8_t invmap[] = { static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple, const struct nf_conntrack_tuple *orig) { - if (orig->dst.u.icmp.type >= sizeof(invmap) - || !invmap[orig->dst.u.icmp.type]) + if (orig->dst.u.icmp.type >= sizeof(invmap) || + !invmap[orig->dst.u.icmp.type]) return false; tuple->src.u.icmp.id = orig->src.u.icmp.id; @@ -101,8 +101,8 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, [ICMP_ADDRESS] = 1 }; - if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) - || !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) { + if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) || + !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) { /* Can't create a new ICMP `conn' with this. */ pr_debug("icmp: can't create new conn with type %u\n", ct->tuplehash[0].tuple.dst.u.icmp.type); @@ -201,11 +201,11 @@ icmp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, } /* Need to track icmp error message? */ - if (icmph->type != ICMP_DEST_UNREACH - && icmph->type != ICMP_SOURCE_QUENCH - && icmph->type != ICMP_TIME_EXCEEDED - && icmph->type != ICMP_PARAMETERPROB - && icmph->type != ICMP_REDIRECT) + if (icmph->type != ICMP_DEST_UNREACH && + icmph->type != ICMP_SOURCE_QUENCH && + icmph->type != ICMP_TIME_EXCEEDED && + icmph->type != ICMP_PARAMETERPROB && + icmph->type != ICMP_REDIRECT) return NF_ACCEPT; return icmp_error_message(net, skb, ctinfo, hooknum); @@ -238,17 +238,17 @@ static const struct nla_policy icmp_nla_policy[CTA_PROTO_MAX+1] = { static int icmp_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *tuple) { - if (!tb[CTA_PROTO_ICMP_TYPE] - || !tb[CTA_PROTO_ICMP_CODE] - || !tb[CTA_PROTO_ICMP_ID]) + if (!tb[CTA_PROTO_ICMP_TYPE] || + !tb[CTA_PROTO_ICMP_CODE] || + !tb[CTA_PROTO_ICMP_ID]) return -EINVAL; tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]); tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]); tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMP_ID]); - if (tuple->dst.u.icmp.type >= sizeof(invmap) - || !invmap[tuple->dst.u.icmp.type]) + if (tuple->dst.u.icmp.type >= sizeof(invmap) || + !invmap[tuple->dst.u.icmp.type]) return -EINVAL; return 0; diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 5f41d017ddd..5678e9562c1 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -197,11 +197,11 @@ nf_nat_out(unsigned int hooknum, (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - if (ct->tuplehash[dir].tuple.src.u3.ip != - ct->tuplehash[!dir].tuple.dst.u3.ip - || ct->tuplehash[dir].tuple.src.u.all != - ct->tuplehash[!dir].tuple.dst.u.all - ) + if ((ct->tuplehash[dir].tuple.src.u3.ip != + ct->tuplehash[!dir].tuple.dst.u3.ip) || + (ct->tuplehash[dir].tuple.src.u.all != + ct->tuplehash[!dir].tuple.dst.u.all) + ) return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP; } #endif diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index cc9f8ef303f..480d7f8c980 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -105,9 +105,9 @@ ip6_packet_match(const struct sk_buff *skb, #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg))) if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, - &ip6info->src), IP6T_INV_SRCIP) - || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, - &ip6info->dst), IP6T_INV_DSTIP)) { + &ip6info->src), IP6T_INV_SRCIP) || + FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, + &ip6info->dst), IP6T_INV_DSTIP)) { dprintf("Source or dest mismatch.\n"); /* dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, @@ -277,11 +277,11 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, } else if (s == e) { (*rulenum)++; - if (s->target_offset == sizeof(struct ip6t_entry) - && strcmp(t->target.u.kernel.target->name, - IP6T_STANDARD_TARGET) == 0 - && t->verdict < 0 - && unconditional(&s->ipv6)) { + if (s->target_offset == sizeof(struct ip6t_entry) && + strcmp(t->target.u.kernel.target->name, + IP6T_STANDARD_TARGET) == 0 && + t->verdict < 0 && + unconditional(&s->ipv6)) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname ? comments[NF_IP6_TRACE_COMMENT_POLICY] @@ -418,8 +418,8 @@ ip6t_do_table(struct sk_buff *skb, back = get_entry(table_base, back->comefrom); continue; } - if (table_base + v != ip6t_next_entry(e) - && !(e->ipv6.flags & IP6T_F_GOTO)) { + if (table_base + v != ip6t_next_entry(e) && + !(e->ipv6.flags & IP6T_F_GOTO)) { /* Save old back ptr in next entry */ struct ip6t_entry *next = ip6t_next_entry(e); next->comefrom = (void *)back - table_base; @@ -505,11 +505,11 @@ mark_source_chains(struct xt_table_info *newinfo, e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); /* Unconditional return/END. */ - if ((e->target_offset == sizeof(struct ip6t_entry) - && (strcmp(t->target.u.user.name, - IP6T_STANDARD_TARGET) == 0) - && t->verdict < 0 - && unconditional(&e->ipv6)) || visited) { + if ((e->target_offset == sizeof(struct ip6t_entry) && + (strcmp(t->target.u.user.name, + IP6T_STANDARD_TARGET) == 0) && + t->verdict < 0 && + unconditional(&e->ipv6)) || visited) { unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, @@ -556,8 +556,8 @@ mark_source_chains(struct xt_table_info *newinfo, int newpos = t->verdict; if (strcmp(t->target.u.user.name, - IP6T_STANDARD_TARGET) == 0 - && newpos >= 0) { + IP6T_STANDARD_TARGET) == 0 && + newpos >= 0) { if (newpos > newinfo->size - sizeof(struct ip6t_entry)) { duprintf("mark_source_chains: " @@ -767,8 +767,8 @@ check_entry_size_and_hooks(struct ip6t_entry *e, { unsigned int h; - if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 - || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { + if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || + (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { duprintf("Bad offset %p\n", e); return -EINVAL; } @@ -1584,8 +1584,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, int ret, off, h; duprintf("check_compat_entry_size_and_hooks %p\n", e); - if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 - || (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) { + if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 || + (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) { duprintf("Bad offset %p, limit = %p\n", e, limit); return -EINVAL; } diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 7018cac4fdd..b285fdf1905 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -249,8 +249,8 @@ static void dump_packet(const struct nf_loginfo *info, /* Max length: 11 "URGP=65535 " */ printk("URGP=%u ", ntohs(th->urg_ptr)); - if ((logflags & IP6T_LOG_TCPOPT) - && th->doff * 4 > sizeof(struct tcphdr)) { + if ((logflags & IP6T_LOG_TCPOPT) && + th->doff * 4 > sizeof(struct tcphdr)) { u_int8_t _opt[60 - sizeof(struct tcphdr)]; const u_int8_t *op; unsigned int i; diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 5a7f00cd15c..8311ca31816 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -223,8 +223,8 @@ static bool reject_tg6_check(const struct xt_tgchk_param *par) return false; } else if (rejinfo->with == IP6T_TCP_RESET) { /* Must specify that it's a TCP packet */ - if (e->ipv6.proto != IPPROTO_TCP - || (e->ipv6.invflags & XT_INV_PROTO)) { + if (e->ipv6.proto != IPPROTO_TCP || + (e->ipv6.invflags & XT_INV_PROTO)) { printk("ip6t_REJECT: TCP_RESET illegal for non-tcp\n"); return false; } diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 3a82f24746b..ac0b7c629d7 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c @@ -77,17 +77,14 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par) ahinfo->hdrres, ah->reserved, !(ahinfo->hdrres && ah->reserved)); - return (ah != NULL) - && - spi_match(ahinfo->spis[0], ahinfo->spis[1], - ntohl(ah->spi), - !!(ahinfo->invflags & IP6T_AH_INV_SPI)) - && - (!ahinfo->hdrlen || - (ahinfo->hdrlen == hdrlen) ^ - !!(ahinfo->invflags & IP6T_AH_INV_LEN)) - && - !(ahinfo->hdrres && ah->reserved); + return (ah != NULL) && + spi_match(ahinfo->spis[0], ahinfo->spis[1], + ntohl(ah->spi), + !!(ahinfo->invflags & IP6T_AH_INV_SPI)) && + (!ahinfo->hdrlen || + (ahinfo->hdrlen == hdrlen) ^ + !!(ahinfo->invflags & IP6T_AH_INV_LEN)) && + !(ahinfo->hdrres && ah->reserved); } static bool ah_mt6_check(const struct xt_mtchk_param *par) diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 673aa0a5084..7b91c2598ed 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c @@ -70,41 +70,36 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par) pr_debug("res %02X %02X%04X %02X ", fraginfo->flags & IP6T_FRAG_RES, fh->reserved, ntohs(fh->frag_off) & 0x6, - !((fraginfo->flags & IP6T_FRAG_RES) - && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); + !((fraginfo->flags & IP6T_FRAG_RES) && + (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); pr_debug("first %02X %02X %02X ", fraginfo->flags & IP6T_FRAG_FST, ntohs(fh->frag_off) & ~0x7, - !((fraginfo->flags & IP6T_FRAG_FST) - && (ntohs(fh->frag_off) & ~0x7))); + !((fraginfo->flags & IP6T_FRAG_FST) && + (ntohs(fh->frag_off) & ~0x7))); pr_debug("mf %02X %02X %02X ", fraginfo->flags & IP6T_FRAG_MF, ntohs(fh->frag_off) & IP6_MF, - !((fraginfo->flags & IP6T_FRAG_MF) - && !((ntohs(fh->frag_off) & IP6_MF)))); + !((fraginfo->flags & IP6T_FRAG_MF) && + !((ntohs(fh->frag_off) & IP6_MF)))); pr_debug("last %02X %02X %02X\n", fraginfo->flags & IP6T_FRAG_NMF, ntohs(fh->frag_off) & IP6_MF, - !((fraginfo->flags & IP6T_FRAG_NMF) - && (ntohs(fh->frag_off) & IP6_MF))); - - return (fh != NULL) - && - id_match(fraginfo->ids[0], fraginfo->ids[1], - ntohl(fh->identification), - !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) - && - !((fraginfo->flags & IP6T_FRAG_RES) - && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) - && - !((fraginfo->flags & IP6T_FRAG_FST) - && (ntohs(fh->frag_off) & ~0x7)) - && - !((fraginfo->flags & IP6T_FRAG_MF) - && !(ntohs(fh->frag_off) & IP6_MF)) - && - !((fraginfo->flags & IP6T_FRAG_NMF) - && (ntohs(fh->frag_off) & IP6_MF)); + !((fraginfo->flags & IP6T_FRAG_NMF) && + (ntohs(fh->frag_off) & IP6_MF))); + + return (fh != NULL) && + id_match(fraginfo->ids[0], fraginfo->ids[1], + ntohl(fh->identification), + !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) && + !((fraginfo->flags & IP6T_FRAG_RES) && + (fh->reserved || (ntohs(fh->frag_off) & 0x6))) && + !((fraginfo->flags & IP6T_FRAG_FST) && + (ntohs(fh->frag_off) & ~0x7)) && + !((fraginfo->flags & IP6T_FRAG_MF) && + !(ntohs(fh->frag_off) & IP6_MF)) && + !((fraginfo->flags & IP6T_FRAG_NMF) && + (ntohs(fh->frag_off) & IP6_MF)); } static bool frag_mt6_check(const struct xt_mtchk_param *par) diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 356b8d6f6ba..b77307fc874 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -92,16 +92,13 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par) !((rtinfo->flags & IP6T_RT_RES) && (((const struct rt0_hdr *)rh)->reserved))); - ret = (rh != NULL) - && + ret = (rh != NULL) && (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], rh->segments_left, - !!(rtinfo->invflags & IP6T_RT_INV_SGS))) - && + !!(rtinfo->invflags & IP6T_RT_INV_SGS))) && (!(rtinfo->flags & IP6T_RT_LEN) || ((rtinfo->hdrlen == hdrlen) ^ - !!(rtinfo->invflags & IP6T_RT_INV_LEN))) - && + !!(rtinfo->invflags & IP6T_RT_INV_LEN))) && (!(rtinfo->flags & IP6T_RT_TYP) || ((rtinfo->rt_type == rh->type) ^ !!(rtinfo->invflags & IP6T_RT_INV_TYP))); diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 6f4383ad86f..ad378efd0eb 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -79,8 +79,8 @@ ip6t_local_out_hook(unsigned int hook, { #if 0 /* root is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) - || ip_hdrlen(skb) < sizeof(struct iphdr)) { + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) { if (net_ratelimit()) printk("ip6t_hook: happy cracking.\n"); return NF_ACCEPT; diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 0ad91433ed6..a929c19d30e 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -102,8 +102,8 @@ ip6t_local_out_hook(unsigned int hook, #if 0 /* root is playing with raw sockets. */ - if (skb->len < sizeof(struct iphdr) - || ip_hdrlen(skb) < sizeof(struct iphdr)) { + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) { if (net_ratelimit()) printk("ip6t_hook: happy cracking.\n"); return NF_ACCEPT; @@ -122,11 +122,11 @@ ip6t_local_out_hook(unsigned int hook, ret = ip6t_do_table(skb, hook, in, out, dev_net(out)->ipv6.ip6table_mangle); - if (ret != NF_DROP && ret != NF_STOLEN - && (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) - || memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) - || skb->mark != mark - || ipv6_hdr(skb)->hop_limit != hop_limit)) + if (ret != NF_DROP && ret != NF_STOLEN && + (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || + memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || + skb->mark != mark || + ipv6_hdr(skb)->hop_limit != hop_limit)) return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; return ret; diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 642dcb127ba..0f3df45718a 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -244,18 +244,18 @@ static const struct nla_policy icmpv6_nla_policy[CTA_PROTO_MAX+1] = { static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], struct nf_conntrack_tuple *tuple) { - if (!tb[CTA_PROTO_ICMPV6_TYPE] - || !tb[CTA_PROTO_ICMPV6_CODE] - || !tb[CTA_PROTO_ICMPV6_ID]) + if (!tb[CTA_PROTO_ICMPV6_TYPE] || + !tb[CTA_PROTO_ICMPV6_CODE] || + !tb[CTA_PROTO_ICMPV6_ID]) return -EINVAL; tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); - if (tuple->dst.u.icmp.type < 128 - || tuple->dst.u.icmp.type - 128 >= sizeof(invmap) - || !invmap[tuple->dst.u.icmp.type - 128]) + if (tuple->dst.u.icmp.type < 128 || + tuple->dst.u.icmp.type - 128 >= sizeof(invmap) || + !invmap[tuple->dst.u.icmp.type - 128]) return -EINVAL; return 0; -- cgit v1.2.3 From 35700212b45ea9f98fa682cfc1bc1a67c9ccc34b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 24 Nov 2009 14:52:52 -0800 Subject: net/ipv6: Move && and || to end of previous line Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/ipv6/ip6_flowlabel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 7712578bdc6..593a67e8d3f 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -377,8 +377,8 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, goto done; fl->share = freq->flr_share; addr_type = ipv6_addr_type(&freq->flr_dst); - if ((addr_type&IPV6_ADDR_MAPPED) - || addr_type == IPV6_ADDR_ANY) { + if ((addr_type & IPV6_ADDR_MAPPED) || + addr_type == IPV6_ADDR_ANY) { err = -EINVAL; goto done; } @@ -421,8 +421,8 @@ static int mem_check(struct sock *sk) if (room <= 0 || ((count >= FL_MAX_PER_SOCK || - (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4) - && !capable(CAP_NET_ADMIN))) + (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4) && + !capable(CAP_NET_ADMIN))) return -ENOBUFS; return 0; -- cgit v1.2.3 From efe117ab8114f47f317b4803e5bc0104420bcba2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 11:06:40 +0100 Subject: mac80211: Speedup ieee80211_remove_interfaces() Speedup ieee80211_remove_interfaces() by factorizing synchronize_rcu() calls Signed-off-by: Eric Dumazet Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/iface.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1bf12a26b45..80c16f6e2af 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -860,22 +860,18 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) void ieee80211_remove_interfaces(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata, *tmp; + LIST_HEAD(unreg_list); ASSERT_RTNL(); + mutex_lock(&local->iflist_mtx); list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { - /* - * we cannot hold the iflist_mtx across unregister_netdevice, - * but we only need to hold it for list modifications to lock - * out readers since we're under the RTNL here as all other - * writers. - */ - mutex_lock(&local->iflist_mtx); list_del(&sdata->list); - mutex_unlock(&local->iflist_mtx); - unregister_netdevice(sdata->dev); + unregister_netdevice_queue(sdata->dev, &unreg_list); } + mutex_unlock(&local->iflist_mtx); + unregister_netdevice_many(&unreg_list); } static u32 ieee80211_idle_off(struct ieee80211_local *local, -- cgit v1.2.3 From 09ad9bc752519cc167d0a573e1acf69b5c707c67 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Nov 2009 15:14:13 -0800 Subject: net: use net_eq to compare nets Generated with the following semantic patch @@ struct net *n1; struct net *n2; @@ - n1 == n2 + net_eq(n1, n2) @@ struct net *n1; struct net *n2; @@ - n1 != n2 + !net_eq(n1, n2) applied over {include,net,drivers/net}. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- drivers/net/hamradio/bpqether.c | 4 ++-- drivers/net/loopback.c | 2 +- drivers/net/wan/hdlc.c | 4 ++-- net/appletalk/ddp.c | 2 +- net/atm/svc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/can/af_can.c | 2 +- net/core/dev.c | 4 ++-- net/core/neighbour.c | 2 +- net/core/net-sysfs.c | 4 ++-- net/core/net_namespace.c | 2 +- net/core/sysctl_net_core.c | 2 +- net/dcb/dcbnl.c | 2 +- net/decnet/af_decnet.c | 2 +- net/decnet/dn_dev.c | 6 +++--- net/decnet/dn_fib.c | 4 ++-- net/decnet/dn_route.c | 4 ++-- net/decnet/dn_table.c | 2 +- net/econet/af_econet.c | 2 +- net/ieee802154/af_ieee802154.c | 2 +- net/ipv4/devinet.c | 2 +- net/ipv4/fib_semantics.c | 4 ++-- net/ipv4/inet_connection_sock.c | 4 ++-- net/ipv4/inet_hashtables.c | 3 ++- net/ipv4/ip_fragment.c | 4 ++-- net/ipv4/ip_input.c | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv4/route.c | 4 ++-- net/ipv4/sysctl_net_ipv4.c | 4 ++-- net/ipv6/addrconf.c | 4 ++-- net/ipv6/ip6_flowlabel.c | 9 +++++---- net/ipv6/netfilter/ip6_queue.c | 2 +- net/ipv6/reassembly.c | 4 ++-- net/ipx/af_ipx.c | 2 +- net/llc/af_llc.c | 2 +- net/netfilter/nfnetlink_log.c | 2 +- net/netlink/af_netlink.c | 2 +- net/netrom/af_netrom.c | 2 +- net/packet/af_packet.c | 6 +++--- net/rose/af_rose.c | 2 +- net/rxrpc/af_rxrpc.c | 2 +- net/sched/act_api.c | 4 ++-- net/sched/cls_api.c | 4 ++-- net/sched/sch_api.c | 10 +++++----- net/tipc/socket.c | 2 +- net/x25/af_x25.c | 2 +- 46 files changed, 74 insertions(+), 72 deletions(-) (limited to 'net') diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index fe893c91a01..76abed9a70b 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -186,7 +186,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty struct ethhdr *eth; struct bpqdev *bpq; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -552,7 +552,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (!dev_is_ethdev(dev)) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 1bc654a73c4..c9f65574378 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -207,7 +207,7 @@ static __net_init int loopback_net_init(struct net *net) out_free_netdev: free_netdev(dev); out: - if (net == &init_net) + if (net_eq(net, &init_net)) panic("loopback: Failed to register netdevice: %d\n", err); return err; } diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index cc07236ea73..9937bbab938 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -57,7 +57,7 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, { struct hdlc_device *hdlc = dev_to_hdlc(dev); - if (dev_net(dev) != &init_net) { + if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(skb); return 0; } @@ -102,7 +102,7 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event, unsigned long flags; int on; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (!(dev->priv_flags & IFF_WAN_HDLC)) diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 73ca4d52492..9fc4da56fb1 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1023,7 +1023,7 @@ static int atalk_create(struct net *net, struct socket *sock, int protocol, struct sock *sk; int rc = -ESOCKTNOSUPPORT; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; /* diff --git a/net/atm/svc.c b/net/atm/svc.c index c7395070ee7..66e1d9b3e5d 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -655,7 +655,7 @@ static int svc_create(struct net *net, struct socket *sock, int protocol, { int error; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; sock->ops = &svc_proto_ops; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index d6ddfa4c447..5588ba69c46 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -805,7 +805,7 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol, struct sock *sk; ax25_cb *ax25; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; switch (sock->type) { diff --git a/net/can/af_can.c b/net/can/af_can.c index 833bd838edc..f3067172886 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -126,7 +126,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol, if (protocol < 0 || protocol >= CAN_NPROTO) return -EINVAL; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; #ifdef CONFIG_MODULES diff --git a/net/core/dev.c b/net/core/dev.c index ccefa2473c3..e65af604141 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -985,7 +985,7 @@ rollback: /* For now only devices in the initial network namespace * are in sysfs. */ - if (net == &init_net) { + if (net_eq(net, &init_net)) { ret = device_rename(&dev->dev, dev->name); if (ret) { memcpy(dev->name, oldname, IFNAMSIZ); @@ -4792,7 +4792,7 @@ static void rollback_registered_many(struct list_head *head) list_for_each_entry_safe(dev, aux, head, unreg_list) { int new_net = 1; list_for_each_entry(fdev, &pernet_list, unreg_list) { - if (dev_net(dev) == dev_net(fdev)) { + if (net_eq(dev_net(dev), dev_net(fdev))) { new_net = 0; dev_put(dev); break; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e587e681969..a08a35bf0a7 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2092,7 +2092,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, if (h > s_h) s_idx = 0; for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) { - if (dev_net(n->dev) != net) + if (!net_eq(dev_net(n->dev), net)) continue; if (idx < s_idx) goto next; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 157645c0da7..fbc1c7472c5 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -525,7 +525,7 @@ void netdev_unregister_kobject(struct net_device * net) kobject_get(&dev->kobj); - if (dev_net(net) != &init_net) + if (!net_eq(dev_net(net), &init_net)) return; device_del(dev); @@ -559,7 +559,7 @@ int netdev_register_kobject(struct net_device *net) #endif #endif /* CONFIG_SYSFS */ - if (dev_net(net) != &init_net) + if (!net_eq(dev_net(net), &init_net)) return 0; return device_add(dev); diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 1c1af2756f3..86ed7f44d08 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -280,7 +280,7 @@ out_undo: list_del(&ops->list); if (ops->exit) { for_each_net(undo_net) { - if (undo_net == net) + if (net_eq(undo_net, net)) goto undone; ops->exit(undo_net); } diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 7db1de0497c..fcfc5458c39 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -134,7 +134,7 @@ static __net_init int sysctl_core_net_init(struct net *net) net->core.sysctl_somaxconn = SOMAXCONN; tbl = netns_core_table; - if (net != &init_net) { + if (!net_eq(net, &init_net)) { tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL); if (tbl == NULL) goto err_dup; diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index ac1205df6c8..2afd617104d 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -1126,7 +1126,7 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) u32 pid = skb ? NETLINK_CB(skb).pid : 0; int ret = -EINVAL; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 9ade3a6de95..2b494fac946 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -680,7 +680,7 @@ static int dn_create(struct net *net, struct socket *sock, int protocol, { struct sock *sk; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; switch(sock->type) { diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 6c916e2b8a8..f20dec9cfa0 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -636,7 +636,7 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) struct dn_ifaddr *ifa, **ifap; int err = -EINVAL; - if (net != &init_net) + if (!net_eq(net, &init_net)) goto errout; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); @@ -675,7 +675,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) struct dn_ifaddr *ifa; int err; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); @@ -789,7 +789,7 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) struct dn_dev *dn_db; struct dn_ifaddr *ifa; - if (net != &init_net) + if (!net_eq(net, &init_net)) return 0; skip_ndevs = cb->args[0]; diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index fd641f65e09..e9d48700e83 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -509,7 +509,7 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void * struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; if (dn_fib_check_attr(r, rta)) @@ -529,7 +529,7 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void * struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; if (dn_fib_check_attr(r, rta)) diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 860286a3921..a03284061a3 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1517,7 +1517,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void struct sk_buff *skb; struct flowi fl; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; memset(&fl, 0, sizeof(fl)); @@ -1602,7 +1602,7 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) int h, s_h; int idx, s_idx; - if (net != &init_net) + if (!net_eq(net, &init_net)) return 0; if (NLMSG_PAYLOAD(cb->nlh, 0) < sizeof(struct rtmsg)) diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 67054b0d550..f281e0f59b0 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -471,7 +471,7 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) struct hlist_node *node; int dumped = 0; - if (net != &init_net) + if (!net_eq(net, &init_net)) return 0; if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 596679803de..29b4931aae5 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -612,7 +612,7 @@ static int econet_create(struct net *net, struct socket *sock, int protocol, struct econet_sock *eo; int err; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; /* Econet only provides datagram services. */ diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index de6e34d2a7f..bad1c49fd96 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -241,7 +241,7 @@ static int ieee802154_create(struct net *net, struct socket *sock, struct proto *proto; const struct proto_ops *ops; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; switch (sock->type) { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 7620382058a..c100709d6dd 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1605,7 +1605,7 @@ static __net_init int devinet_init_net(struct net *net) all = &ipv4_devconf; dflt = &ipv4_devconf_dflt; - if (net != &init_net) { + if (!net_eq(net, &init_net)) { all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL); if (all == NULL) goto err_alloc_all; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 9b096d6ff3f..ed19aa6919c 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -228,7 +228,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi) head = &fib_info_hash[hash]; hlist_for_each_entry(fi, node, head, fib_hash) { - if (fi->fib_net != nfi->fib_net) + if (!net_eq(fi->fib_net, nfi->fib_net)) continue; if (fi->fib_nhs != nfi->fib_nhs) continue; @@ -1047,7 +1047,7 @@ int fib_sync_down_addr(struct net *net, __be32 local) return 0; hlist_for_each_entry(fi, node, head, fib_lhash) { - if (fi->fib_net != net) + if (!net_eq(fi->fib_net, net)) continue; if (fi->fib_prefsrc == local) { fi->fib_flags |= RTNH_F_DEAD; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 26fb50e9131..9b35c56d102 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -112,7 +112,7 @@ again: hashinfo->bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) - if (ib_net(tb) == net && tb->port == rover) { + if (net_eq(ib_net(tb), net) && tb->port == rover) { if (tb->fastreuse > 0 && sk->sk_reuse && sk->sk_state != TCP_LISTEN && @@ -158,7 +158,7 @@ have_snum: hashinfo->bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) - if (ib_net(tb) == net && tb->port == snum) + if (net_eq(ib_net(tb), net) && tb->port == snum) goto tb_found; } tb = NULL; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 47ad7aab51e..94ef51aa5bc 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -454,7 +454,8 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, * unique enough. */ inet_bind_bucket_for_each(tb, node, &head->chain) { - if (ib_net(tb) == net && tb->port == port) { + if (net_eq(ib_net(tb), net) && + tb->port == port) { if (tb->fastreuse >= 0) goto next_port; WARN_ON(hlist_empty(&tb->owners)); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b007f8af6e1..1472d8e3c19 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -658,7 +658,7 @@ static int ip4_frags_ns_ctl_register(struct net *net) struct ctl_table_header *hdr; table = ip4_frags_ns_ctl_table; - if (net != &init_net) { + if (!net_eq(net, &init_net)) { table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL); if (table == NULL) goto err_alloc; @@ -676,7 +676,7 @@ static int ip4_frags_ns_ctl_register(struct net *net) return 0; err_reg: - if (net != &init_net) + if (!net_eq(net, &init_net)) kfree(table); err_alloc: return -ENOMEM; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index fdf51badc8e..c29de9879fd 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -164,7 +164,7 @@ int ip_call_ra_chain(struct sk_buff *skb) if (sk && inet_sk(sk)->inet_num == protocol && (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) && - sock_net(sk) == dev_net(dev)) { + net_eq(sock_net(sk), dev_net(dev))) { if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) { read_unlock(&ip_ra_lock); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index c156db21598..884f0859cb3 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -500,7 +500,7 @@ ipq_rcv_nl_event(struct notifier_block *this, if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL && n->pid) { write_lock_bh(&queue_lock); - if ((n->net == &init_net) && (n->pid == peer_pid)) + if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7547944ea9b..aea7bb369cf 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -703,7 +703,7 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) static inline int compare_netns(struct rtable *rt1, struct rtable *rt2) { - return dev_net(rt1->u.dst.dev) == dev_net(rt2->u.dst.dev); + return net_eq(dev_net(rt1->u.dst.dev), dev_net(rt2->u.dst.dev)); } static inline int rt_is_expired(struct rtable *rth) @@ -3310,7 +3310,7 @@ static __net_init int sysctl_route_net_init(struct net *net) struct ctl_table *tbl; tbl = ipv4_route_flush_table; - if (net != &init_net) { + if (!net_eq(net, &init_net)) { tbl = kmemdup(tbl, sizeof(ipv4_route_flush_table), GFP_KERNEL); if (tbl == NULL) goto err_dup; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 2dcf04d9b00..c00323bae04 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -818,7 +818,7 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) struct ctl_table *table; table = ipv4_net_table; - if (net != &init_net) { + if (!net_eq(net, &init_net)) { table = kmemdup(table, sizeof(ipv4_net_table), GFP_KERNEL); if (table == NULL) goto err_alloc; @@ -849,7 +849,7 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) return 0; err_reg: - if (net != &init_net) + if (!net_eq(net, &init_net)) kfree(table); err_alloc: return -ENOMEM; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 522bdc77206..b1ce8fc6204 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4498,7 +4498,7 @@ static int addrconf_init_net(struct net *net) all = &ipv6_devconf; dflt = &ipv6_devconf_dflt; - if (net != &init_net) { + if (!net_eq(net, &init_net)) { all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL); if (all == NULL) goto err_alloc_all; @@ -4546,7 +4546,7 @@ static void addrconf_exit_net(struct net *net) __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); __addrconf_sysctl_unregister(net->ipv6.devconf_all); #endif - if (net != &init_net) { + if (!net_eq(net, &init_net)) { kfree(net->ipv6.devconf_dflt); kfree(net->ipv6.devconf_all); } diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 593a67e8d3f..6e7bffa2205 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -67,7 +67,7 @@ static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) struct ip6_flowlabel *fl; for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { - if (fl->label == label && fl->fl_net == net) + if (fl->label == label && net_eq(fl->fl_net, net)) return fl; } return NULL; @@ -163,7 +163,8 @@ static void ip6_fl_purge(struct net *net) struct ip6_flowlabel *fl, **flp; flp = &fl_ht[i]; while ((fl = *flp) != NULL) { - if (fl->fl_net == net && atomic_read(&fl->users) == 0) { + if (net_eq(fl->fl_net, net) && + atomic_read(&fl->users) == 0) { *flp = fl->next; fl_free(fl); atomic_dec(&fl_size); @@ -630,7 +631,7 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { fl = fl_ht[state->bucket]; - while (fl && fl->fl_net != net) + while (fl && !net_eq(fl->fl_net, net)) fl = fl->next; if (fl) break; @@ -645,7 +646,7 @@ static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flo fl = fl->next; try_again: - while (fl && fl->fl_net != net) + while (fl && !net_eq(fl->fl_net, net)) fl = fl->next; while (!fl) { diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 1cf3f0c6a95..4c7a18abcaf 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -502,7 +502,7 @@ ipq_rcv_nl_event(struct notifier_block *this, if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW && n->pid) { write_lock_bh(&queue_lock); - if ((n->net == &init_net) && (n->pid == peer_pid)) + if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index dce699fb267..45efc39753e 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -681,7 +681,7 @@ static int ip6_frags_ns_sysctl_register(struct net *net) struct ctl_table_header *hdr; table = ip6_frags_ns_ctl_table; - if (net != &init_net) { + if (!net_eq(net, &init_net)) { table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL); if (table == NULL) goto err_alloc; @@ -699,7 +699,7 @@ static int ip6_frags_ns_sysctl_register(struct net *net) return 0; err_reg: - if (net != &init_net) + if (!net_eq(net, &init_net)) kfree(table); err_alloc: return -ENOMEM; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 975c5a366e5..f9759b54a6d 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1362,7 +1362,7 @@ static int ipx_create(struct net *net, struct socket *sock, int protocol, int rc = -ESOCKTNOSUPPORT; struct sock *sk; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; /* diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 5266c286b26..3a66546cad0 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -158,7 +158,7 @@ static int llc_ui_create(struct net *net, struct socket *sock, int protocol, if (!capable(CAP_NET_RAW)) return -EPERM; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) { diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index f900dc3194a..49005482e39 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -678,7 +678,7 @@ nfulnl_rcv_nl_event(struct notifier_block *this, struct hlist_head *head = &instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if ((n->net == &init_net) && + if ((net_eq(n->net, &init_net)) && (n->pid == inst->peer_pid)) __instance_destroy(inst); } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index eff5b0ddc5c..a4957bf2ca6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1092,7 +1092,7 @@ static inline int do_one_set_err(struct sock *sk, if (sk == p->exclude_sk) goto out; - if (sock_net(sk) != sock_net(p->exclude_sk)) + if (!net_eq(sock_net(sk), sock_net(p->exclude_sk))) goto out; if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 4bdd5697f63..71604c6613b 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -431,7 +431,7 @@ static int nr_create(struct net *net, struct socket *sock, int protocol, struct sock *sk; struct nr_sock *nr; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; if (sock->type != SOCK_SEQPACKET || protocol != 0) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c620bd9ae3d..940fc20b2b5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -365,7 +365,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, if (skb->pkt_type == PACKET_LOOPBACK) goto out; - if (dev_net(dev) != sock_net(sk)) + if (!net_eq(dev_net(dev), sock_net(sk))) goto out; skb = skb_share_check(skb, GFP_ATOMIC); @@ -553,7 +553,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev_net(dev) != sock_net(sk)) + if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; skb->dev = dev; @@ -674,7 +674,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev_net(dev) != sock_net(sk)) + if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; if (dev->header_ops) { diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 4de4287fec3..8feb9e5d662 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -518,7 +518,7 @@ static int rose_create(struct net *net, struct socket *sock, int protocol, struct sock *sk; struct rose_sock *rose; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; if (sock->type != SOCK_SEQPACKET || protocol != 0) diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index f978d02a248..287b1415cee 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -616,7 +616,7 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol, _enter("%p,%d", sock, protocol); - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; /* we support transport protocol UDP only */ diff --git a/net/sched/act_api.c b/net/sched/act_api.c index ca2e1fd2bf6..2a740035aa6 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -969,7 +969,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) u32 pid = skb ? NETLINK_CB(skb).pid : 0; int ret = 0, ovr = 0; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL); @@ -1052,7 +1052,7 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh); struct nlattr *kind = find_dump_kind(cb->nlh); - if (net != &init_net) + if (!net_eq(net, &init_net)) return 0; if (kind == NULL) { diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index c024da77824..3725d8fa29d 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -137,7 +137,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) int err; int tp_created = 0; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; replay: @@ -418,7 +418,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) const struct Qdisc_class_ops *cops; struct tcf_dump_args arg; - if (net != &init_net) + if (!net_eq(net, &init_net)) return 0; if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 876ba4bb6ae..75fd1c672c6 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -947,7 +947,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) struct Qdisc *p = NULL; int err; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) @@ -1009,7 +1009,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) struct Qdisc *q, *p; int err; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; replay: @@ -1274,7 +1274,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) int s_idx, s_q_idx; struct net_device *dev; - if (net != &init_net) + if (!net_eq(net, &init_net)) return 0; s_idx = cb->args[0]; @@ -1334,7 +1334,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) u32 qid = TC_H_MAJ(clid); int err; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EINVAL; if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) @@ -1576,7 +1576,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) struct net_device *dev; int t, s_t; - if (net != &init_net) + if (!net_eq(net, &init_net)) return 0; if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d00c2119faf..eca5eb0dab0 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -195,7 +195,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol, /* Validate arguments */ - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; if (unlikely(protocol != 0)) diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index ac7dba46fa3..2a3a513af3c 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -514,7 +514,7 @@ static int x25_create(struct net *net, struct socket *sock, int protocol, struct x25_sock *x25; int rc = -ESOCKTNOSUPPORT; - if (net != &init_net) + if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; if (sock->type != SOCK_SEQPACKET || protocol) -- cgit v1.2.3 From a661c4199b300503dae694efa21f1354f763b97c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 25 Nov 2009 15:40:35 -0800 Subject: net: convert /proc/net/rt_acct to seq_file Rewrite statistics accumulation to be in terms of structure fields, not raw u32 additions. Keep them in same order, though. This is the last user of create_proc_read_entry() in net/, please NAK all new ones as well as all new ->write_proc, ->read_proc and create_proc_entry() users. Cc me if there are problems. :-) Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipv4/route.c | 68 +++++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index aea7bb369cf..9889fbd9648 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -513,43 +513,42 @@ static const struct file_operations rt_cpu_seq_fops = { }; #ifdef CONFIG_NET_CLS_ROUTE -static int ip_rt_acct_read(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) -{ - unsigned int i; - - if ((offset & 3) || (length & 3)) - return -EIO; - - if (offset >= sizeof(struct ip_rt_acct) * 256) { - *eof = 1; - return 0; - } - - if (offset + length >= sizeof(struct ip_rt_acct) * 256) { - length = sizeof(struct ip_rt_acct) * 256 - offset; - *eof = 1; +static int rt_acct_proc_show(struct seq_file *m, void *v) +{ + struct ip_rt_acct *dst, *src; + unsigned int i, j; + + dst = kcalloc(256, sizeof(struct ip_rt_acct), GFP_KERNEL); + if (!dst) + return -ENOMEM; + + for_each_possible_cpu(i) { + src = (struct ip_rt_acct *)per_cpu_ptr(ip_rt_acct, i); + for (j = 0; j < 256; j++) { + dst[j].o_bytes += src[j].o_bytes; + dst[j].o_packets += src[j].o_packets; + dst[j].i_bytes += src[j].i_bytes; + dst[j].i_packets += src[j].i_packets; + } } - offset /= sizeof(u32); - - if (length > 0) { - u32 *dst = (u32 *) buffer; - - *start = buffer; - memset(dst, 0, length); - - for_each_possible_cpu(i) { - unsigned int j; - u32 *src; + seq_write(m, dst, 256 * sizeof(struct ip_rt_acct)); + kfree(dst); + return 0; +} - src = ((u32 *) per_cpu_ptr(ip_rt_acct, i)) + offset; - for (j = 0; j < length/4; j++) - dst[j] += src[j]; - } - } - return length; +static int rt_acct_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, rt_acct_proc_show, NULL); } + +static const struct file_operations rt_acct_proc_fops = { + .owner = THIS_MODULE, + .open = rt_acct_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif static int __net_init ip_rt_do_proc_init(struct net *net) @@ -567,8 +566,7 @@ static int __net_init ip_rt_do_proc_init(struct net *net) goto err2; #ifdef CONFIG_NET_CLS_ROUTE - pde = create_proc_read_entry("rt_acct", 0, net->proc_net, - ip_rt_acct_read, NULL); + pde = proc_create("rt_acct", 0, net->proc_net, &rt_acct_proc_fops); if (!pde) goto err3; #endif -- cgit v1.2.3 From 4447bb33f09444920a8f1d89e1540137429351b6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 25 Nov 2009 00:29:52 +0000 Subject: xfrm: Store aalg in xfrm_state with a user specified truncation length Adding a xfrm_state requires an authentication algorithm specified either as xfrm_algo or as xfrm_algo_auth with a specific truncation length. For compatibility, both attributes are dumped to userspace, and we also accept both attributes, but prefer the new syntax. If no truncation length is specified, or the authentication algorithm is specified using xfrm_algo, the truncation length from the algorithm description in the kernel is used. Signed-off-by: Martin Willi Signed-off-by: David S. Miller --- include/net/xfrm.h | 12 ++++- net/xfrm/xfrm_state.c | 2 +- net/xfrm/xfrm_user.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 133 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 93d184b91a8..6d85861ab99 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -162,7 +162,7 @@ struct xfrm_state { struct xfrm_lifetime_cfg lft; /* Data for transformer */ - struct xfrm_algo *aalg; + struct xfrm_algo_auth *aalg; struct xfrm_algo *ealg; struct xfrm_algo *calg; struct xfrm_algo_aead *aead; @@ -1532,12 +1532,22 @@ static inline int xfrm_alg_len(struct xfrm_algo *alg) return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); } +static inline int xfrm_alg_auth_len(struct xfrm_algo_auth *alg) +{ + return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); +} + #ifdef CONFIG_XFRM_MIGRATE static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig) { return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL); } +static inline struct xfrm_algo_auth *xfrm_algo_auth_clone(struct xfrm_algo_auth *orig) +{ + return kmemdup(orig, xfrm_alg_auth_len(orig), GFP_KERNEL); +} + static inline void xfrm_states_put(struct xfrm_state **states, int n) { int i; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index e9ac0cec087..d847f1a52b4 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1114,7 +1114,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) x->props.saddr = orig->props.saddr; if (orig->aalg) { - x->aalg = xfrm_algo_clone(orig->aalg); + x->aalg = xfrm_algo_auth_clone(orig->aalg); if (!x->aalg) goto error; } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b95a2d64eb5..fb42d778d27 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -62,6 +62,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) return 0; } +static int verify_auth_trunc(struct nlattr **attrs) +{ + struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC]; + struct xfrm_algo_auth *algp; + + if (!rt) + return 0; + + algp = nla_data(rt); + if (nla_len(rt) < xfrm_alg_auth_len(algp)) + return -EINVAL; + + algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; + return 0; +} + static int verify_aead(struct nlattr **attrs) { struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; @@ -128,7 +144,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, err = -EINVAL; switch (p->id.proto) { case IPPROTO_AH: - if (!attrs[XFRMA_ALG_AUTH] || + if ((!attrs[XFRMA_ALG_AUTH] && + !attrs[XFRMA_ALG_AUTH_TRUNC]) || attrs[XFRMA_ALG_AEAD] || attrs[XFRMA_ALG_CRYPT] || attrs[XFRMA_ALG_COMP]) @@ -139,10 +156,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, if (attrs[XFRMA_ALG_COMP]) goto out; if (!attrs[XFRMA_ALG_AUTH] && + !attrs[XFRMA_ALG_AUTH_TRUNC] && !attrs[XFRMA_ALG_CRYPT] && !attrs[XFRMA_ALG_AEAD]) goto out; if ((attrs[XFRMA_ALG_AUTH] || + attrs[XFRMA_ALG_AUTH_TRUNC] || attrs[XFRMA_ALG_CRYPT]) && attrs[XFRMA_ALG_AEAD]) goto out; @@ -152,6 +171,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, if (!attrs[XFRMA_ALG_COMP] || attrs[XFRMA_ALG_AEAD] || attrs[XFRMA_ALG_AUTH] || + attrs[XFRMA_ALG_AUTH_TRUNC] || attrs[XFRMA_ALG_CRYPT]) goto out; break; @@ -161,6 +181,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, case IPPROTO_ROUTING: if (attrs[XFRMA_ALG_COMP] || attrs[XFRMA_ALG_AUTH] || + attrs[XFRMA_ALG_AUTH_TRUNC] || attrs[XFRMA_ALG_AEAD] || attrs[XFRMA_ALG_CRYPT] || attrs[XFRMA_ENCAP] || @@ -176,6 +197,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, if ((err = verify_aead(attrs))) goto out; + if ((err = verify_auth_trunc(attrs))) + goto out; if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) goto out; if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) @@ -229,6 +252,66 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, return 0; } +static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props, + struct nlattr *rta) +{ + struct xfrm_algo *ualg; + struct xfrm_algo_auth *p; + struct xfrm_algo_desc *algo; + + if (!rta) + return 0; + + ualg = nla_data(rta); + + algo = xfrm_aalg_get_byname(ualg->alg_name, 1); + if (!algo) + return -ENOSYS; + *props = algo->desc.sadb_alg_id; + + p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL); + if (!p) + return -ENOMEM; + + strcpy(p->alg_name, algo->name); + p->alg_key_len = ualg->alg_key_len; + p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; + memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8); + + *algpp = p; + return 0; +} + +static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props, + struct nlattr *rta) +{ + struct xfrm_algo_auth *p, *ualg; + struct xfrm_algo_desc *algo; + + if (!rta) + return 0; + + ualg = nla_data(rta); + + algo = xfrm_aalg_get_byname(ualg->alg_name, 1); + if (!algo) + return -ENOSYS; + if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits) + return -EINVAL; + *props = algo->desc.sadb_alg_id; + + p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL); + if (!p) + return -ENOMEM; + + strcpy(p->alg_name, algo->name); + if (!p->alg_trunc_len) + p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; + + *algpp = p; + return 0; +} + static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, struct nlattr *rta) { @@ -332,10 +415,14 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, if ((err = attach_aead(&x->aead, &x->props.ealgo, attrs[XFRMA_ALG_AEAD]))) goto error; - if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, - xfrm_aalg_get_byname, - attrs[XFRMA_ALG_AUTH]))) + if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo, + attrs[XFRMA_ALG_AUTH_TRUNC]))) goto error; + if (!x->props.aalgo) { + if ((err = attach_auth(&x->aalg, &x->props.aalgo, + attrs[XFRMA_ALG_AUTH]))) + goto error; + } if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, xfrm_ealg_get_byname, attrs[XFRMA_ALG_CRYPT]))) @@ -548,6 +635,24 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) return 0; } +static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb) +{ + struct xfrm_algo *algo; + struct nlattr *nla; + + nla = nla_reserve(skb, XFRMA_ALG_AUTH, + sizeof(*algo) + (auth->alg_key_len + 7) / 8); + if (!nla) + return -EMSGSIZE; + + algo = nla_data(nla); + strcpy(algo->alg_name, auth->alg_name); + memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8); + algo->alg_key_len = auth->alg_key_len; + + return 0; +} + /* Don't change this without updating xfrm_sa_len! */ static int copy_to_user_state_extra(struct xfrm_state *x, struct xfrm_usersa_info *p, @@ -563,8 +668,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, if (x->aead) NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); - if (x->aalg) - NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); + if (x->aalg) { + if (copy_to_user_auth(x->aalg, skb)) + goto nla_put_failure; + + NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC, + xfrm_alg_auth_len(x->aalg), x->aalg); + } if (x->ealg) NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); if (x->calg) @@ -2117,8 +2227,11 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) size_t l = 0; if (x->aead) l += nla_total_size(aead_len(x->aead)); - if (x->aalg) - l += nla_total_size(xfrm_alg_len(x->aalg)); + if (x->aalg) { + l += nla_total_size(sizeof(struct xfrm_algo) + + (x->aalg->alg_key_len + 7) / 8); + l += nla_total_size(xfrm_alg_auth_len(x->aalg)); + } if (x->ealg) l += nla_total_size(xfrm_alg_len(x->ealg)); if (x->calg) -- cgit v1.2.3 From 8f8a088c2127c729638da8f2d33860e346c01eda Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 25 Nov 2009 00:29:53 +0000 Subject: xfrm: Use the user specified truncation length in ESP and AH Instead of using the hardcoded truncation for authentication algorithms, use the truncation length specified on xfrm_state. Signed-off-by: Martin Willi Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 2 +- net/ipv4/esp4.c | 2 +- net/ipv6/ah6.c | 2 +- net/ipv6/esp6.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index d07b0c1dd35..7ed3e4ae93a 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -444,7 +444,7 @@ static int ah_init_state(struct xfrm_state *x) } ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; - ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; + ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 12f7287e902..1948895beb6 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -530,7 +530,7 @@ static int esp_init_authenc(struct xfrm_state *x) } err = crypto_aead_setauthsize( - aead, aalg_desc->uinfo.auth.icv_truncbits / 8); + aead, x->aalg->alg_trunc_len / 8); if (err) goto free_key; } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 0f526f8ea51..c2f300c314b 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -667,7 +667,7 @@ static int ah6_init_state(struct xfrm_state *x) } ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; - ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; + ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index af597c73ebe..668a46b655e 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -473,7 +473,7 @@ static int esp_init_authenc(struct xfrm_state *x) } err = crypto_aead_setauthsize( - aead, aalg_desc->uinfo.auth.icv_truncbits / 8); + aead, x->aalg->alg_trunc_len / 8); if (err) goto free_key; } -- cgit v1.2.3 From bc74b0c8af17458ecae77f725e507ab5fd100105 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 25 Nov 2009 00:58:39 +0000 Subject: xfrm: Add SHA384 and SHA512 HMAC authentication algorithms to XFRM These algorithms use a truncation of 192/256 bits, as specified in RFC4868. Signed-off-by: Martin Willi Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_algo.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'net') diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index b39341072aa..ef8d61d5046 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -199,6 +199,40 @@ static struct xfrm_algo_desc aalg_list[] = { .sadb_alg_maxbits = 256 } }, +{ + .name = "hmac(sha384)", + + .uinfo = { + .auth = { + .icv_truncbits = 192, + .icv_fullbits = 384, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_AALG_SHA2_384HMAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 384, + .sadb_alg_maxbits = 384 + } +}, +{ + .name = "hmac(sha512)", + + .uinfo = { + .auth = { + .icv_truncbits = 256, + .icv_fullbits = 512, + } + }, + + .desc = { + .sadb_alg_id = SADB_X_AALG_SHA2_512HMAC, + .sadb_alg_ivlen = 0, + .sadb_alg_minbits = 512, + .sadb_alg_maxbits = 512 + } +}, { .name = "hmac(rmd160)", .compat = "rmd160", -- cgit v1.2.3 From 445409602c09219767c06497c0dc2285eac244ed Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 26 Nov 2009 06:07:08 +0000 Subject: veth: move loopback logic to common location The veth driver contains code to forward an skb from the start_xmit function of one network device into the receive path of another device. Moving that code into a common location lets us reuse the code for direct forwarding of data between macvlan ports, and possibly in other drivers. Signed-off-by: Arnd Bergmann Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/veth.c | 17 +++-------------- include/linux/netdevice.h | 2 ++ net/core/dev.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2d657f2314c..6c4b5a2d787 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -155,8 +155,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) struct veth_net_stats *stats, *rcv_stats; int length, cpu; - skb_orphan(skb); - priv = netdev_priv(dev); rcv = priv->peer; rcv_priv = netdev_priv(rcv); @@ -168,20 +166,12 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) if (!(rcv->flags & IFF_UP)) goto tx_drop; - if (skb->len > (rcv->mtu + MTU_PAD)) - goto rx_drop; - - skb->tstamp.tv64 = 0; - skb->pkt_type = PACKET_HOST; - skb->protocol = eth_type_trans(skb, rcv); if (dev->features & NETIF_F_NO_CSUM) skb->ip_summed = rcv_priv->ip_summed; - skb->mark = 0; - secpath_reset(skb); - nf_reset(skb); - - length = skb->len; + length = skb->len + ETH_HLEN; + if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) + goto rx_drop; stats->tx_bytes += length; stats->tx_packets++; @@ -189,7 +179,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) rcv_stats->rx_bytes += length; rcv_stats->rx_packets++; - netif_rx(skb); return NETDEV_TX_OK; tx_drop: diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 97873e31661..9428793775a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1562,6 +1562,8 @@ extern int dev_set_mac_address(struct net_device *, extern int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq); +extern int dev_forward_skb(struct net_device *dev, + struct sk_buff *skb); extern int netdev_budget; diff --git a/net/core/dev.c b/net/core/dev.c index e65af604141..7775e8b48de 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -105,6 +105,7 @@ #include #include #include +#include #include #include #include @@ -1419,6 +1420,45 @@ static inline void net_timestamp(struct sk_buff *skb) skb->tstamp.tv64 = 0; } +/** + * dev_forward_skb - loopback an skb to another netif + * + * @dev: destination network device + * @skb: buffer to forward + * + * return values: + * NET_RX_SUCCESS (no congestion) + * NET_RX_DROP (packet was dropped) + * + * dev_forward_skb can be used for injecting an skb from the + * start_xmit function of one device into the receive queue + * of another device. + * + * The receiving device may be in another namespace, so + * we have to clear all information in the skb that could + * impact namespace isolation. + */ +int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) +{ + skb_orphan(skb); + + if (!(dev->flags & IFF_UP)) + return NET_RX_DROP; + + if (skb->len > (dev->mtu + dev->hard_header_len)) + return NET_RX_DROP; + + skb_dst_drop(skb); + skb->tstamp.tv64 = 0; + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, dev); + skb->mark = 0; + secpath_reset(skb); + nf_reset(skb); + return netif_rx(skb); +} +EXPORT_SYMBOL_GPL(dev_forward_skb); + /* * Support routine. Sends outgoing frames to any network * taps currently in use. -- cgit v1.2.3 From 5e7565930524410f097f5b04f8aba663089a6ffc Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 25 Nov 2009 07:54:54 +0000 Subject: vlan: support "loose binding" to the underlying network device Currently the UP/DOWN state of VLANs is synchronized to the state of the underlying device, meaning all VLANs are set down once the underlying device is set down. This causes all routes to the VLAN devices to vanish. Add a flag to specify a "loose binding" mode, in which only the operstate is transfered, but the VLAN device state is independant. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 1 + net/8021q/vlan.c | 9 +++++++-- net/8021q/vlan_dev.c | 6 ++++-- net/8021q/vlan_netlink.c | 3 ++- 4 files changed, 14 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 153f6b9e722..3d870fda8c4 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -339,6 +339,7 @@ enum vlan_ioctl_cmds { enum vlan_flags { VLAN_FLAG_REORDER_HDR = 0x1, VLAN_FLAG_GVRP = 0x2, + VLAN_FLAG_LOOSE_BINDING = 0x4, }; enum vlan_name_types { diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 1483243edf1..225aa2fac0e 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -431,6 +431,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, struct vlan_group *grp; int i, flgs; struct net_device *vlandev; + struct vlan_dev_info *vlan; LIST_HEAD(list); if (is_vlan_dev(dev)) @@ -507,7 +508,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, if (!(flgs & IFF_UP)) continue; - dev_change_flags(vlandev, flgs & ~IFF_UP); + vlan = vlan_dev_info(vlandev); + if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) + dev_change_flags(vlandev, flgs & ~IFF_UP); vlan_transfer_operstate(dev, vlandev); } break; @@ -523,7 +526,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, if (flgs & IFF_UP) continue; - dev_change_flags(vlandev, flgs | IFF_UP); + vlan = vlan_dev_info(vlandev); + if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) + dev_change_flags(vlandev, flgs | IFF_UP); vlan_transfer_operstate(dev, vlandev); } break; diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index de0dc6bacbe..b7889782047 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -431,7 +431,8 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask) struct vlan_dev_info *vlan = vlan_dev_info(dev); u32 old_flags = vlan->flags; - if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) + if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | + VLAN_FLAG_LOOSE_BINDING)) return -EINVAL; vlan->flags = (old_flags & ~mask) | (flags & mask); @@ -456,7 +457,8 @@ static int vlan_dev_open(struct net_device *dev) struct net_device *real_dev = vlan->real_dev; int err; - if (!(real_dev->flags & IFF_UP)) + if (!(real_dev->flags & IFF_UP) && + !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) return -ENETDOWN; if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 3c9cf6a8e7f..ddc105734af 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -60,7 +60,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) if (data[IFLA_VLAN_FLAGS]) { flags = nla_data(data[IFLA_VLAN_FLAGS]); if ((flags->flags & flags->mask) & - ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) + ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | + VLAN_FLAG_LOOSE_BINDING)) return -EINVAL; } -- cgit v1.2.3 From e60d7443e00a72a2c056950cdaab79c7b077f3d4 Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Wed, 25 Nov 2009 15:13:00 +0100 Subject: wireless : use a dedicated workqueue for cfg80211. This patch moves the works cleanup, scan and events to a cfg80211 dedicated workqueue. Platform driver like eeepc-laptop ought to use works to rfkill (as new rfkill does lock in rfkill_unregister and the platform driver is called from rfkill_switch_all which also lock the same mutex). This raise a new issue in itself that the work scheduled by the platform driver to the global worqueue calls wiphy_unregister which flush_work scan and event works (which thus flush works on the global workqueue inside a work on the global workqueue) and also put on hold the wdev_cleanup_work (which prevents the dev_put on netdev thus indefinite Usage count error on wifi device). Signed-off-by: Johannes Berg Signed-off-by: Alban Browaeys Signed-off-by: John W. Linville --- net/wireless/core.c | 12 +++++++++++- net/wireless/core.h | 2 ++ net/wireless/ibss.c | 2 +- net/wireless/scan.c | 2 +- net/wireless/sme.c | 6 +++--- 5 files changed, 18 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/wireless/core.c b/net/wireless/core.c index fe6f402a22a..c2a2c563d21 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -45,6 +45,9 @@ DEFINE_MUTEX(cfg80211_mutex); /* for debugfs */ static struct dentry *ieee80211_debugfs_dir; +/* for the cleanup, scan and event works */ +struct workqueue_struct *cfg80211_wq; + /* requires cfg80211_mutex to be held! */ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) { @@ -727,7 +730,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NETDEV_DOWN: dev_hold(dev); - schedule_work(&wdev->cleanup_work); + queue_work(cfg80211_wq, &wdev->cleanup_work); break; case NETDEV_UP: /* @@ -845,8 +848,14 @@ static int __init cfg80211_init(void) if (err) goto out_fail_reg; + cfg80211_wq = create_singlethread_workqueue("cfg80211"); + if (!cfg80211_wq) + goto out_fail_wq; + return 0; +out_fail_wq: + regulatory_exit(); out_fail_reg: debugfs_remove(ieee80211_debugfs_dir); out_fail_nl80211: @@ -868,5 +877,6 @@ static void cfg80211_exit(void) wiphy_sysfs_exit(); regulatory_exit(); unregister_pernet_device(&cfg80211_pernet_ops); + destroy_workqueue(cfg80211_wq); } module_exit(cfg80211_exit); diff --git a/net/wireless/core.h b/net/wireless/core.h index a9db9e6255b..4ef3efc9410 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -91,6 +91,8 @@ bool wiphy_idx_valid(int wiphy_idx) return (wiphy_idx >= 0); } + +extern struct workqueue_struct *cfg80211_wq; extern struct mutex cfg80211_mutex; extern struct list_head cfg80211_rdev_list; extern int cfg80211_rdev_list_generation; diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 34dfc93fa71..6ef5a491fb4 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -70,7 +70,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_ibss_joined); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 227d57b8dc4..df26228db1b 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -88,7 +88,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); request->aborted = aborted; - schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); + queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); } EXPORT_SYMBOL(cfg80211_scan_done); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0115d07d2c1..2333d78187e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -488,7 +488,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_connect_result); @@ -583,7 +583,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_roamed); @@ -681,7 +681,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); - schedule_work(&rdev->event_work); + queue_work(cfg80211_wq, &rdev->event_work); } EXPORT_SYMBOL(cfg80211_disconnected); -- cgit v1.2.3 From 8c0c709eea5cbab97fb464cd68b06f24acc58ee1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Nov 2009 17:46:15 +0100 Subject: mac80211: move cmntr flag out of rx flags The RX flags should soon be used only for flags that cannot change within an a-MPDU, so move the cooked monitor flag into the RX status flags. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 4 ++++ net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/rx.c | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3754ea405c8..1d75b960da0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -513,6 +513,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index * @RX_FLAG_40MHZ: HT40 (40 MHz) was used * @RX_FLAG_SHORT_GI: Short guard interval was used + * @RX_FLAG_INTERNAL_CMTR: set internally after frame was reported + * on cooked monitor to avoid double-reporting it for multiple + * virtual interfaces */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -526,6 +529,7 @@ enum mac80211_rx_flags { RX_FLAG_HT = 1<<9, RX_FLAG_40MHZ = 1<<10, RX_FLAG_SHORT_GI = 1<<11, + RX_FLAG_INTERNAL_CMTR = 1<<12, }; /** diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 04093e84ebd..ba5d3637b95 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -163,8 +163,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result; /* frame is destined to interface currently processed (incl. multicast frames) */ #define IEEE80211_RX_RA_MATCH BIT(1) #define IEEE80211_RX_AMSDU BIT(2) -#define IEEE80211_RX_CMNTR_REPORTED BIT(3) -#define IEEE80211_RX_FRAGMENTED BIT(4) +#define IEEE80211_RX_FRAGMENTED BIT(3) struct ieee80211_rx_data { struct sk_buff *skb; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 96f13ad05d3..097bb0343b9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1868,7 +1868,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct net_device *prev_dev = NULL; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - if (rx->flags & IEEE80211_RX_CMNTR_REPORTED) + if (status->flag & RX_FLAG_INTERNAL_CMTR) goto out_free_skb; if (skb_headroom(skb) < sizeof(*rthdr) && @@ -1929,7 +1929,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, } else goto out_free_skb; - rx->flags |= IEEE80211_RX_CMNTR_REPORTED; + status->flag |= RX_FLAG_INTERNAL_CMTR; return; out_free_skb: -- cgit v1.2.3 From 1edfb1afba2f6e4114ff09f2e3bc948fcae0c419 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Nov 2009 17:46:16 +0100 Subject: mac80211: move aMPDU RX reorder code This code should be part of RX handlers, so move it to the place where it belongs without changing it. A follow-up patch will do the changes to hook it up. The sole purpose of this code move is to make the other patch readable, it doesn't change the code at all except that it now requires a different static function declaration (which will go away too). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 459 +++++++++++++++++++++++++++--------------------------- 1 file changed, 229 insertions(+), 230 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 097bb0343b9..d71a63e1fd6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -27,9 +27,9 @@ #include "tkip.h" #include "wme.h" -static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - u16 head_seq_num); +static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_rate *rate); /* * monitor mode reception @@ -534,6 +534,232 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) return RX_CONTINUE; } +#define SEQ_MODULO 0x1000 +#define SEQ_MASK 0xfff + +static inline int seq_less(u16 sq1, u16 sq2) +{ + return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); +} + +static inline u16 seq_inc(u16 sq) +{ + return (sq + 1) & SEQ_MASK; +} + +static inline u16 seq_sub(u16 sq1, u16 sq2) +{ + return (sq1 - sq2) & SEQ_MASK; +} + + +static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + int index) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate = NULL; + struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; + struct ieee80211_rx_status *status; + + if (!skb) + goto no_frame; + + status = IEEE80211_SKB_RXCB(skb); + + /* release the reordered frames to stack */ + sband = hw->wiphy->bands[status->band]; + if (!(status->flag & RX_FLAG_HT)) + rate = &sband->bitrates[status->rate_idx]; + __ieee80211_rx_handle_packet(hw, skb, rate); + tid_agg_rx->stored_mpdu_num--; + tid_agg_rx->reorder_buf[index] = NULL; + +no_frame: + tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); +} + +static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + u16 head_seq_num) +{ + int index; + + while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { + index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % + tid_agg_rx->buf_size; + ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + } +} + +/* + * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If + * the skb was added to the buffer longer than this time ago, the earlier + * frames that have not yet been received are assumed to be lost and the skb + * can be released for processing. This may also release other skb's from the + * reorder buffer if there are no additional gaps between the frames. + */ +#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) + +/* + * As this function belongs to the RX path it must be under + * rcu_read_lock protection. It returns false if the frame + * can be processed immediately, true if it was consumed. + */ +static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 sc = le16_to_cpu(hdr->seq_ctrl); + u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; + u16 head_seq_num, buf_size; + int index; + + buf_size = tid_agg_rx->buf_size; + head_seq_num = tid_agg_rx->head_seq_num; + + /* frame with out of date sequence number */ + if (seq_less(mpdu_seq_num, head_seq_num)) { + dev_kfree_skb(skb); + return true; + } + + /* + * If frame the sequence number exceeds our buffering window + * size release some previous frames to make room for this one. + */ + if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { + head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); + /* release stored frames up to new head to stack */ + ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); + } + + /* Now the new frame is always in the range of the reordering buffer */ + + index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; + + /* check if we already stored this frame */ + if (tid_agg_rx->reorder_buf[index]) { + dev_kfree_skb(skb); + return true; + } + + /* + * If the current MPDU is in the right order and nothing else + * is stored we can process it directly, no need to buffer it. + */ + if (mpdu_seq_num == tid_agg_rx->head_seq_num && + tid_agg_rx->stored_mpdu_num == 0) { + tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); + return false; + } + + /* put the frame in the reordering buffer */ + tid_agg_rx->reorder_buf[index] = skb; + tid_agg_rx->reorder_time[index] = jiffies; + tid_agg_rx->stored_mpdu_num++; + /* release the buffer until next missing frame */ + index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % + tid_agg_rx->buf_size; + if (!tid_agg_rx->reorder_buf[index] && + tid_agg_rx->stored_mpdu_num > 1) { + /* + * No buffers ready to be released, but check whether any + * frames in the reorder buffer have timed out. + */ + int j; + int skipped = 1; + for (j = (index + 1) % tid_agg_rx->buf_size; j != index; + j = (j + 1) % tid_agg_rx->buf_size) { + if (!tid_agg_rx->reorder_buf[j]) { + skipped++; + continue; + } + if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + + HT_RX_REORDER_BUF_TIMEOUT)) + break; + +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "%s: release an RX reorder " + "frame due to timeout on earlier " + "frames\n", + wiphy_name(hw->wiphy)); +#endif + ieee80211_release_reorder_frame(hw, tid_agg_rx, j); + + /* + * Increment the head seq# also for the skipped slots. + */ + tid_agg_rx->head_seq_num = + (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; + skipped = 0; + } + } else while (tid_agg_rx->reorder_buf[index]) { + ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % + tid_agg_rx->buf_size; + } + + return true; +} + +/* + * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns + * true if the MPDU was buffered, false if it should be processed. + */ +static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, + struct sk_buff *skb) +{ + struct ieee80211_hw *hw = &local->hw; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct sta_info *sta; + struct tid_ampdu_rx *tid_agg_rx; + u16 sc; + int tid; + + if (!ieee80211_is_data_qos(hdr->frame_control)) + return false; + + /* + * filter the QoS data rx stream according to + * STA/TID and check if this STA/TID is on aggregation + */ + + sta = sta_info_get(local, hdr->addr2); + if (!sta) + return false; + + tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + + if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) + return false; + + tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; + + /* qos null data frames are excluded */ + if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) + return false; + + /* new, potentially un-ordered, ampdu frame - process it */ + + /* reset session timer */ + if (tid_agg_rx->timeout) + mod_timer(&tid_agg_rx->session_timer, + TU_TO_EXP_TIME(tid_agg_rx->timeout)); + + /* if this mpdu is fragmented - terminate rx aggregation session */ + sc = le16_to_cpu(hdr->seq_ctrl); + if (sc & IEEE80211_SCTL_FRAG) { + ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, + tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); + dev_kfree_skb(skb); + return true; + } + + return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb); +} static ieee80211_rx_result debug_noinline ieee80211_rx_h_check(struct ieee80211_rx_data *rx) @@ -2187,233 +2413,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, dev_kfree_skb(skb); } -#define SEQ_MODULO 0x1000 -#define SEQ_MASK 0xfff - -static inline int seq_less(u16 sq1, u16 sq2) -{ - return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); -} - -static inline u16 seq_inc(u16 sq) -{ - return (sq + 1) & SEQ_MASK; -} - -static inline u16 seq_sub(u16 sq1, u16 sq2) -{ - return (sq1 - sq2) & SEQ_MASK; -} - - -static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - int index) -{ - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate = NULL; - struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; - struct ieee80211_rx_status *status; - - if (!skb) - goto no_frame; - - status = IEEE80211_SKB_RXCB(skb); - - /* release the reordered frames to stack */ - sband = hw->wiphy->bands[status->band]; - if (!(status->flag & RX_FLAG_HT)) - rate = &sband->bitrates[status->rate_idx]; - __ieee80211_rx_handle_packet(hw, skb, rate); - tid_agg_rx->stored_mpdu_num--; - tid_agg_rx->reorder_buf[index] = NULL; - -no_frame: - tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); -} - -static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - u16 head_seq_num) -{ - int index; - - while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { - index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % - tid_agg_rx->buf_size; - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); - } -} - -/* - * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If - * the skb was added to the buffer longer than this time ago, the earlier - * frames that have not yet been received are assumed to be lost and the skb - * can be released for processing. This may also release other skb's from the - * reorder buffer if there are no additional gaps between the frames. - */ -#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) - -/* - * As this function belongs to the RX path it must be under - * rcu_read_lock protection. It returns false if the frame - * can be processed immediately, true if it was consumed. - */ -static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 sc = le16_to_cpu(hdr->seq_ctrl); - u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; - u16 head_seq_num, buf_size; - int index; - - buf_size = tid_agg_rx->buf_size; - head_seq_num = tid_agg_rx->head_seq_num; - - /* frame with out of date sequence number */ - if (seq_less(mpdu_seq_num, head_seq_num)) { - dev_kfree_skb(skb); - return true; - } - - /* - * If frame the sequence number exceeds our buffering window - * size release some previous frames to make room for this one. - */ - if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { - head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); - /* release stored frames up to new head to stack */ - ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); - } - - /* Now the new frame is always in the range of the reordering buffer */ - - index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - - /* check if we already stored this frame */ - if (tid_agg_rx->reorder_buf[index]) { - dev_kfree_skb(skb); - return true; - } - - /* - * If the current MPDU is in the right order and nothing else - * is stored we can process it directly, no need to buffer it. - */ - if (mpdu_seq_num == tid_agg_rx->head_seq_num && - tid_agg_rx->stored_mpdu_num == 0) { - tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); - return false; - } - - /* put the frame in the reordering buffer */ - tid_agg_rx->reorder_buf[index] = skb; - tid_agg_rx->reorder_time[index] = jiffies; - tid_agg_rx->stored_mpdu_num++; - /* release the buffer until next missing frame */ - index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % - tid_agg_rx->buf_size; - if (!tid_agg_rx->reorder_buf[index] && - tid_agg_rx->stored_mpdu_num > 1) { - /* - * No buffers ready to be released, but check whether any - * frames in the reorder buffer have timed out. - */ - int j; - int skipped = 1; - for (j = (index + 1) % tid_agg_rx->buf_size; j != index; - j = (j + 1) % tid_agg_rx->buf_size) { - if (!tid_agg_rx->reorder_buf[j]) { - skipped++; - continue; - } - if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + - HT_RX_REORDER_BUF_TIMEOUT)) - break; - -#ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: release an RX reorder " - "frame due to timeout on earlier " - "frames\n", - wiphy_name(hw->wiphy)); -#endif - ieee80211_release_reorder_frame(hw, tid_agg_rx, j); - - /* - * Increment the head seq# also for the skipped slots. - */ - tid_agg_rx->head_seq_num = - (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; - skipped = 0; - } - } else while (tid_agg_rx->reorder_buf[index]) { - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); - index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % - tid_agg_rx->buf_size; - } - - return true; -} - -/* - * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns - * true if the MPDU was buffered, false if it should be processed. - */ -static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, - struct sk_buff *skb) -{ - struct ieee80211_hw *hw = &local->hw; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct sta_info *sta; - struct tid_ampdu_rx *tid_agg_rx; - u16 sc; - int tid; - - if (!ieee80211_is_data_qos(hdr->frame_control)) - return false; - - /* - * filter the QoS data rx stream according to - * STA/TID and check if this STA/TID is on aggregation - */ - - sta = sta_info_get(local, hdr->addr2); - if (!sta) - return false; - - tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; - - if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) - return false; - - tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; - - /* qos null data frames are excluded */ - if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) - return false; - - /* new, potentially un-ordered, ampdu frame - process it */ - - /* reset session timer */ - if (tid_agg_rx->timeout) - mod_timer(&tid_agg_rx->session_timer, - TU_TO_EXP_TIME(tid_agg_rx->timeout)); - - /* if this mpdu is fragmented - terminate rx aggregation session */ - sc = le16_to_cpu(hdr->seq_ctrl); - if (sc & IEEE80211_SCTL_FRAG) { - ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, - tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); - dev_kfree_skb(skb); - return true; - } - - return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb); -} - /* * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. -- cgit v1.2.3 From 2569a826de16ff82302a8a091228275be1aa911c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Nov 2009 17:46:17 +0100 Subject: mac80211: correctly place aMPDU RX reorder code As indicated by the comment, the aMPDU RX reorder code should logically be after ieee80211_rx_h_check(). The previous patch moved the code there, and this patch now hooks it up in that place by introducing a list of skbs that are then processed by the remaining handlers. The list may be empty if the function is buffering the skb to release it later. The only change needed to the RX data is that the crypto handler needs to clear the key that may be set from a previous loop iteration, and that not everything can be in the rx flags now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/rx.c | 168 +++++++++++++++++++++++++-------------------- 2 files changed, 96 insertions(+), 73 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ba5d3637b95..7d3178f1b44 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -164,6 +164,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result; #define IEEE80211_RX_RA_MATCH BIT(1) #define IEEE80211_RX_AMSDU BIT(2) #define IEEE80211_RX_FRAGMENTED BIT(3) +/* only add flags here that do not change with subframes of an aMPDU */ struct ieee80211_rx_data { struct sk_buff *skb; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d71a63e1fd6..57b8a0a4277 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -27,10 +27,6 @@ #include "tkip.h" #include "wme.h" -static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_rate *rate); - /* * monitor mode reception * @@ -555,7 +551,8 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, struct tid_ampdu_rx *tid_agg_rx, - int index) + int index, + struct sk_buff_head *frames) { struct ieee80211_supported_band *sband; struct ieee80211_rate *rate = NULL; @@ -571,9 +568,9 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, sband = hw->wiphy->bands[status->band]; if (!(status->flag & RX_FLAG_HT)) rate = &sband->bitrates[status->rate_idx]; - __ieee80211_rx_handle_packet(hw, skb, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; + skb_queue_tail(frames, skb); no_frame: tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); @@ -581,14 +578,15 @@ no_frame: static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, struct tid_ampdu_rx *tid_agg_rx, - u16 head_seq_num) + u16 head_seq_num, + struct sk_buff_head *frames) { int index; while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); } } @@ -608,7 +606,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, */ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, struct tid_ampdu_rx *tid_agg_rx, - struct sk_buff *skb) + struct sk_buff *skb, + struct sk_buff_head *frames) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 sc = le16_to_cpu(hdr->seq_ctrl); @@ -632,7 +631,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); /* release stored frames up to new head to stack */ - ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); + ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num, + frames); } /* Now the new frame is always in the range of the reordering buffer */ @@ -687,7 +687,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, "frames\n", wiphy_name(hw->wiphy)); #endif - ieee80211_release_reorder_frame(hw, tid_agg_rx, j); + ieee80211_release_reorder_frame(hw, tid_agg_rx, + j, frames); /* * Increment the head seq# also for the skipped slots. @@ -697,7 +698,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, skipped = 0; } } else while (tid_agg_rx->reorder_buf[index]) { - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames); index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; } @@ -709,38 +710,39 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns * true if the MPDU was buffered, false if it should be processed. */ -static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, - struct sk_buff *skb) +static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, + struct sk_buff_head *frames) { + struct sk_buff *skb = rx->skb; + struct ieee80211_local *local = rx->local; struct ieee80211_hw *hw = &local->hw; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct sta_info *sta; + struct sta_info *sta = rx->sta; struct tid_ampdu_rx *tid_agg_rx; u16 sc; int tid; if (!ieee80211_is_data_qos(hdr->frame_control)) - return false; + goto dont_reorder; /* * filter the QoS data rx stream according to * STA/TID and check if this STA/TID is on aggregation */ - sta = sta_info_get(local, hdr->addr2); if (!sta) - return false; + goto dont_reorder; tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) - return false; + goto dont_reorder; tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; /* qos null data frames are excluded */ if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) - return false; + goto dont_reorder; /* new, potentially un-ordered, ampdu frame - process it */ @@ -755,10 +757,14 @@ static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); dev_kfree_skb(skb); - return true; + return; } - return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb); + if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) + return; + + dont_reorder: + __skb_queue_tail(frames, skb); } static ieee80211_rx_result debug_noinline @@ -863,6 +869,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_CONTINUE; + /* start without a key */ + rx->key = NULL; + if (rx->sta) stakey = rcu_dereference(rx->sta->key); @@ -1815,7 +1824,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) } static ieee80211_rx_result debug_noinline -ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) +ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) { struct ieee80211_local *local = rx->local; struct ieee80211_hw *hw = &local->hw; @@ -1845,7 +1854,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) TU_TO_EXP_TIME(tid_agg_rx->timeout)); /* release stored frames up to start of BAR */ - ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); + ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, + frames); kfree_skb(skb); return RX_QUEUED; } @@ -2168,8 +2178,11 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_rate *rate) { + struct sk_buff_head reorder_release; ieee80211_rx_result res = RX_DROP_MONITOR; + __skb_queue_head_init(&reorder_release); + rx->skb = skb; rx->sdata = sdata; @@ -2177,50 +2190,72 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, do { \ res = rxh(rx); \ if (res != RX_CONTINUE) \ - goto rxh_done; \ + goto rxh_next; \ } while (0); + /* + * NB: the rxh_next label works even if we jump + * to it from here because then the list will + * be empty, which is a trivial check + */ CALL_RXH(ieee80211_rx_h_passive_scan) CALL_RXH(ieee80211_rx_h_check) - CALL_RXH(ieee80211_rx_h_decrypt) - CALL_RXH(ieee80211_rx_h_check_more_data) - CALL_RXH(ieee80211_rx_h_sta_process) - CALL_RXH(ieee80211_rx_h_defragment) - CALL_RXH(ieee80211_rx_h_ps_poll) - CALL_RXH(ieee80211_rx_h_michael_mic_verify) - /* must be after MMIC verify so header is counted in MPDU mic */ - CALL_RXH(ieee80211_rx_h_remove_qos_control) - CALL_RXH(ieee80211_rx_h_amsdu) + + ieee80211_rx_reorder_ampdu(rx, &reorder_release); + + while ((skb = __skb_dequeue(&reorder_release))) { + /* + * all the other fields are valid across frames + * that belong to an aMPDU since they are on the + * same TID from the same station + */ + rx->skb = skb; + + CALL_RXH(ieee80211_rx_h_decrypt) + CALL_RXH(ieee80211_rx_h_check_more_data) + CALL_RXH(ieee80211_rx_h_sta_process) + CALL_RXH(ieee80211_rx_h_defragment) + CALL_RXH(ieee80211_rx_h_ps_poll) + CALL_RXH(ieee80211_rx_h_michael_mic_verify) + /* must be after MMIC verify so header is counted in MPDU mic */ + CALL_RXH(ieee80211_rx_h_remove_qos_control) + CALL_RXH(ieee80211_rx_h_amsdu) #ifdef CONFIG_MAC80211_MESH - if (ieee80211_vif_is_mesh(&sdata->vif)) - CALL_RXH(ieee80211_rx_h_mesh_fwding); + if (ieee80211_vif_is_mesh(&sdata->vif)) + CALL_RXH(ieee80211_rx_h_mesh_fwding); #endif - CALL_RXH(ieee80211_rx_h_data) - CALL_RXH(ieee80211_rx_h_ctrl) - CALL_RXH(ieee80211_rx_h_action) - CALL_RXH(ieee80211_rx_h_mgmt) + CALL_RXH(ieee80211_rx_h_data) + + /* special treatment -- needs the queue */ + res = ieee80211_rx_h_ctrl(rx, &reorder_release); + if (res != RX_CONTINUE) + goto rxh_next; + + CALL_RXH(ieee80211_rx_h_action) + CALL_RXH(ieee80211_rx_h_mgmt) #undef CALL_RXH - rxh_done: - switch (res) { - case RX_DROP_MONITOR: - I802_DEBUG_INC(sdata->local->rx_handlers_drop); - if (rx->sta) - rx->sta->rx_dropped++; - /* fall through */ - case RX_CONTINUE: - ieee80211_rx_cooked_monitor(rx, rate); - break; - case RX_DROP_UNUSABLE: - I802_DEBUG_INC(sdata->local->rx_handlers_drop); - if (rx->sta) - rx->sta->rx_dropped++; - dev_kfree_skb(rx->skb); - break; - case RX_QUEUED: - I802_DEBUG_INC(sdata->local->rx_handlers_queued); - break; + rxh_next: + switch (res) { + case RX_DROP_MONITOR: + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; + /* fall through */ + case RX_CONTINUE: + ieee80211_rx_cooked_monitor(rx, rate); + break; + case RX_DROP_UNUSABLE: + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; + dev_kfree_skb(rx->skb); + break; + case RX_QUEUED: + I802_DEBUG_INC(sdata->local->rx_handlers_queued); + break; + } } } @@ -2494,20 +2529,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) return; } - /* - * In theory, the block ack reordering should happen after duplicate - * removal (ieee80211_rx_h_check(), which is an RX handler). As such, - * the call to ieee80211_rx_reorder_ampdu() should really be moved to - * happen as a new RX handler between ieee80211_rx_h_check and - * ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for - * the time being, the call can be here since RX reorder buf processing - * will implicitly skip duplicates. We could, in theory at least, - * process frames that ieee80211_rx_h_passive_scan would drop (e.g., - * frames from other than operational channel), but that should not - * happen in normal networks. - */ - if (!ieee80211_rx_reorder_ampdu(local, skb)) - __ieee80211_rx_handle_packet(hw, skb, rate); + __ieee80211_rx_handle_packet(hw, skb, rate); rcu_read_unlock(); -- cgit v1.2.3 From f911ab83a2c07118dc605d643545647cef6f2322 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Nov 2009 19:07:20 +0100 Subject: mac80211: log more data when tracing Enable logging of more configuration data when tracing is enabled. Except for the channel frequency this is only useful with the binary trace format, but that can be recorded and replayed with trace-cmd and I will be working on a plugin that reports all the information. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/driver-trace.h | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index b8fef1d1136..ee94ea0c67e 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -131,17 +131,35 @@ TRACE_EVENT(drv_config, LOCAL_ENTRY __field(u32, changed) __field(int, ret) + __field(u32, flags) + __field(int, power_level) + __field(int, dynamic_ps_timeout) + __field(int, max_sleep_period) + __field(u16, listen_interval) + __field(u8, long_frame_max_tx_count) + __field(u8, short_frame_max_tx_count) + __field(int, center_freq) + __field(int, channel_type) ), TP_fast_assign( LOCAL_ASSIGN; __entry->changed = changed; __entry->ret = ret; + __entry->flags = local->hw.conf.flags; + __entry->power_level = local->hw.conf.power_level; + __entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout; + __entry->max_sleep_period = local->hw.conf.max_sleep_period; + __entry->listen_interval = local->hw.conf.listen_interval; + __entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count; + __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count; + __entry->center_freq = local->hw.conf.channel->center_freq; + __entry->channel_type = local->hw.conf.channel_type; ), TP_printk( - LOCAL_PR_FMT " ch:%#x ret:%d", - LOCAL_PR_ARG, __entry->changed, __entry->ret + LOCAL_PR_FMT " ch:%#x freq:%d ret:%d", + LOCAL_PR_ARG, __entry->changed, __entry->center_freq, __entry->ret ) ); @@ -167,6 +185,8 @@ TRACE_EVENT(drv_bss_info_changed, __field(u64, timestamp) __field(u32, basic_rates) __field(u32, changed) + __field(bool, enable_beacon) + __field(u16, ht_operation_mode) ), TP_fast_assign( @@ -183,6 +203,8 @@ TRACE_EVENT(drv_bss_info_changed, __entry->assoc_cap = info->assoc_capability; __entry->timestamp = info->timestamp; __entry->basic_rates = info->basic_rates; + __entry->enable_beacon = info->enable_beacon; + __entry->ht_operation_mode = info->ht_operation_mode; ), TP_printk( -- cgit v1.2.3 From 67fbb16be69d138a3b6645ec5395b487cb915c58 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 23:59:15 +0100 Subject: nl80211: PMKSA caching support This is an interface to set, delete and flush PMKIDs through nl80211. Main users would be fullmac devices which firmwares are capable of generating the RSN IEs for the re-association requests, e.g. iwmc3200wifi. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 2 + include/linux/nl80211.h | 11 +++++ include/net/cfg80211.h | 28 +++++++++++ net/wireless/nl80211.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) (limited to 'net') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index afa8e0ac27a..d9724a28c0c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1266,6 +1266,8 @@ enum ieee80211_sa_query_action { #define WLAN_MAX_KEY_LEN 32 +#define WLAN_PMKID_LEN 16 + /** * ieee80211_get_qos_ctl - get pointer to qos control bytes * @hdr: the frame diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 45db17f81aa..da8ea2e1927 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -349,6 +349,10 @@ enum nl80211_commands { NL80211_CMD_GET_SURVEY, NL80211_CMD_NEW_SURVEY_RESULTS, + NL80211_CMD_SET_PMKSA, + NL80211_CMD_DEL_PMKSA, + NL80211_CMD_FLUSH_PMKSA, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -598,6 +602,10 @@ enum nl80211_commands { * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute * containing info as possible, see &enum survey_info. * + * @NL80211_ATTR_PMKID: PMK material for PMKSA caching. + * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can + * cache, a wiphy attribute. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -732,6 +740,9 @@ enum nl80211_attrs { NL80211_ATTR_SURVEY_INFO, + NL80211_ATTR_PMKID, + NL80211_ATTR_MAX_NUM_PMKIDS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a6492e9bca9..0884b9a0f77 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -871,6 +871,19 @@ struct cfg80211_bitrate_mask { u32 fixed; /* fixed bitrate, 0 == not fixed */ u32 maxrate; /* in kbps, 0 == no limit */ }; +/** + * struct cfg80211_pmksa - PMK Security Association + * + * This structure is passed to the set/del_pmksa() method for PMKSA + * caching. + * + * @bssid: The AP's BSSID. + * @pmkid: The PMK material itself. + */ +struct cfg80211_pmksa { + u8 *bssid; + u8 *pmkid; +}; /** * struct cfg80211_ops - backend description for wireless configuration @@ -976,6 +989,13 @@ struct cfg80211_bitrate_mask { * @dump_survey: get site survey information. * * @testmode_cmd: run a test mode command + * + * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac + * devices running firmwares capable of generating the (re) association + * RSN IE. It allows for faster roaming between WPA2 BSSIDs. + * @del_pmksa: Delete a cached PMKID. + * @flush_pmksa: Flush all cached PMKIDs. + * */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy); @@ -1097,6 +1117,12 @@ struct cfg80211_ops { int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, int idx, struct survey_info *info); + int (*set_pmksa)(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + int (*del_pmksa)(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa); + int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); + /* some temporary stuff to finish wext */ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); @@ -1195,6 +1221,8 @@ struct wiphy { char fw_version[ETHTOOL_BUSINFO_LEN]; u32 hw_version; + u8 max_num_pmkids; + /* If multiple wiphys are registered and you're handed e.g. * a regular netdev with assigned ieee80211_ptr, you won't * know whether it points to a wiphy your driver has registered diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 149539ade15..a6028433e3a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -139,6 +139,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, [NL80211_ATTR_PID] = { .type = NLA_U32 }, [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, + [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, + .len = WLAN_PMKID_LEN }, }; /* policy for the attributes */ @@ -450,6 +452,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, sizeof(u32) * dev->wiphy.n_cipher_suites, dev->wiphy.cipher_suites); + NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, + dev->wiphy.max_num_pmkids); + nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); if (!nl_modes) goto nla_put_failure; @@ -561,6 +566,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); CMD(join_ibss, JOIN_IBSS); + CMD(set_pmksa, SET_PMKSA); + CMD(del_pmksa, DEL_PMKSA); + CMD(flush_pmksa, FLUSH_PMKSA); if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); @@ -4221,6 +4229,99 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) = NULL; + int err; + struct net_device *dev; + struct cfg80211_pmksa pmksa; + + memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_PMKID]) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto out_rtnl; + + pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); + pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + err = -EOPNOTSUPP; + goto out; + } + + switch (info->genlhdr->cmd) { + case NL80211_CMD_SET_PMKSA: + rdev_ops = rdev->ops->set_pmksa; + break; + case NL80211_CMD_DEL_PMKSA: + rdev_ops = rdev->ops->del_pmksa; + break; + default: + WARN_ON(1); + break; + } + + if (!rdev_ops) { + err = -EOPNOTSUPP; + goto out; + } + + err = rdev_ops(&rdev->wiphy, dev, &pmksa); + + out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); + out_rtnl: + rtnl_unlock(); + + return err; +} + +static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + int err; + struct net_device *dev; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto out_rtnl; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + err = -EOPNOTSUPP; + goto out; + } + + if (!rdev->ops->flush_pmksa) { + err = -EOPNOTSUPP; + goto out; + } + + err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); + + out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); + out_rtnl: + rtnl_unlock(); + + return err; + +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -4465,6 +4566,25 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .dumpit = nl80211_dump_survey, }, + { + .cmd = NL80211_CMD_SET_PMKSA, + .doit = nl80211_setdel_pmksa, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DEL_PMKSA, + .doit = nl80211_setdel_pmksa, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_FLUSH_PMKSA, + .doit = nl80211_flush_pmksa, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", -- cgit v1.2.3 From 2944b2c2d2dd884c550163c698577132588277d8 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 25 Nov 2009 00:01:01 +0100 Subject: cfg80211: Add PMKSA wext compatibility handler With the addition of the *_pmksa cfg80211 ops, we can now add the corresponding wireless extensions compatibility handler. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/wireless/wext-compat.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'net') diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 29091ac9f98..584eb4826e0 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1401,6 +1401,47 @@ int cfg80211_wext_giwessid(struct net_device *dev, } EXPORT_SYMBOL_GPL(cfg80211_wext_giwessid); +int cfg80211_wext_siwpmksa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct cfg80211_pmksa cfg_pmksa; + struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; + + memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa)); + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + cfg_pmksa.bssid = pmksa->bssid.sa_data; + cfg_pmksa.pmkid = pmksa->pmkid; + + switch (pmksa->cmd) { + case IW_PMKSA_ADD: + if (!rdev->ops->set_pmksa) + return -EOPNOTSUPP; + + return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa); + + case IW_PMKSA_REMOVE: + if (!rdev->ops->del_pmksa) + return -EOPNOTSUPP; + + return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa); + + case IW_PMKSA_FLUSH: + if (!rdev->ops->flush_pmksa) + return -EOPNOTSUPP; + + return rdev->ops->flush_pmksa(&rdev->wiphy, dev); + + default: + return -EOPNOTSUPP; + } +} + static const iw_handler cfg80211_handlers[] = { [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, @@ -1433,6 +1474,7 @@ static const iw_handler cfg80211_handlers[] = { [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, + [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, }; const struct iw_handler_def cfg80211_wext_handler = { -- cgit v1.2.3 From 2f5517aefcfbdd7fdf0f03b13d292a10d445887f Mon Sep 17 00:00:00 2001 From: andrew hendry Date: Tue, 24 Nov 2009 15:15:26 +0000 Subject: X25: Move SYSCTL ifdefs into header Moves the CONFIG_SYSCTL ifdefs in x25_init into header. Signed-off-by: Andrew Hendry Acked-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/net/x25.h | 6 ++++++ net/x25/af_x25.c | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/x25.h b/include/net/x25.h index 2cda0401156..9baa07dc7d1 100644 --- a/include/net/x25.h +++ b/include/net/x25.h @@ -287,8 +287,14 @@ extern unsigned long x25_display_timer(struct sock *); extern void x25_check_rbuf(struct sock *); /* sysctl_net_x25.c */ +#ifdef CONFIG_SYSCTL extern void x25_register_sysctl(void); extern void x25_unregister_sysctl(void); +#else +static inline void x25_register_sysctl(void) {}; +static inline void x25_unregister_sysctl(void) {}; +#endif /* CONFIG_SYSCTL */ + struct x25_skb_cb { unsigned flags; }; diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 2a3a513af3c..f327ef5cb0e 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1729,9 +1729,7 @@ static int __init x25_init(void) printk(KERN_INFO "X.25 for Linux Version 0.2\n"); -#ifdef CONFIG_SYSCTL x25_register_sysctl(); -#endif x25_proc_init(); out: return rc; @@ -1744,9 +1742,7 @@ static void __exit x25_exit(void) x25_link_free(); x25_route_free(); -#ifdef CONFIG_SYSCTL x25_unregister_sysctl(); -#endif unregister_netdevice_notifier(&x25_dev_notifier); -- cgit v1.2.3 From 1fd975a0520cdb27681855d5a18526e328d36b5c Mon Sep 17 00:00:00 2001 From: andrew hendry Date: Tue, 24 Nov 2009 15:15:42 +0000 Subject: X25: Check for errors in x25_init Adds error checking to x25_init. Signed-off-by: Andrew Hendry Signed-off-by: David S. Miller --- net/x25/af_x25.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index f327ef5cb0e..e3219e4cd04 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1721,18 +1721,31 @@ static int __init x25_init(void) if (rc != 0) goto out; - sock_register(&x25_family_ops); + rc = sock_register(&x25_family_ops); + if (rc != 0) + goto out_proto; dev_add_pack(&x25_packet_type); - register_netdevice_notifier(&x25_dev_notifier); + rc = register_netdevice_notifier(&x25_dev_notifier); + if (rc != 0) + goto out_sock; printk(KERN_INFO "X.25 for Linux Version 0.2\n"); x25_register_sysctl(); - x25_proc_init(); + rc = x25_proc_init(); + if (rc != 0) + goto out_dev; out: return rc; +out_dev: + unregister_netdevice_notifier(&x25_dev_notifier); +out_sock: + sock_unregister(AF_X25); +out_proto: + proto_unregister(&x25_proto); + goto out; } module_init(x25_init); -- cgit v1.2.3 From 429d33ace5ce6122817f8abe9d170eaa55dc3af9 Mon Sep 17 00:00:00 2001 From: andrew hendry Date: Tue, 24 Nov 2009 15:16:05 +0000 Subject: X25: Fix oops and refcnt problems from x25_dev_get Calls to x25_dev_get check for dev = NULL which was not set. It allowed x25 to set routes and ioctls on down interfaces. This caused oopses and refcnt problems on device_unregister. Signed-off-by: Andrew Hendry Signed-off-by: David S. Miller --- net/x25/x25_route.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c index 66961ea28c9..b95fae9ab39 100644 --- a/net/x25/x25_route.c +++ b/net/x25/x25_route.c @@ -136,8 +136,10 @@ struct net_device *x25_dev_get(char *devname) #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) && dev->type != ARPHRD_ETHER #endif - ))) + ))){ dev_put(dev); + dev = NULL; + } return dev; } -- cgit v1.2.3 From 3291b9db567e1ec38362024049cbd02987b1e277 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 29 Nov 2009 00:44:33 -0800 Subject: pktgen: NUMA aware pktgen threads are bound to given CPU, we can allocate memory for these threads in a NUMA aware way. After a pktgen session on two threads, we can check flows memory was allocated on right node, instead of a not related one. # grep pktgen_thread_write /proc/vmallocinfo 0xffffc90007204000-0xffffc90007385000 1576960 pktgen_thread_write+0x3a4/0x6b0 [pktgen] pages=384 vmalloc N0=384 0xffffc90007386000-0xffffc90007507000 1576960 pktgen_thread_write+0x3a4/0x6b0 [pktgen] pages=384 vmalloc N1=384 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/pktgen.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b44104d3e6b..19ee493ec17 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3626,6 +3626,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) { struct pktgen_dev *pkt_dev; int err; + int node = cpu_to_node(t->cpu); /* We don't allow a device to be on several threads */ @@ -3635,12 +3636,13 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) return -EBUSY; } - pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL); + pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); if (!pkt_dev) return -ENOMEM; strcpy(pkt_dev->odevname, ifname); - pkt_dev->flows = vmalloc(MAX_CFLOWS * sizeof(struct flow_state)); + pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state), + node); if (pkt_dev->flows == NULL) { kfree(pkt_dev); return -ENOMEM; @@ -3702,7 +3704,8 @@ static int __init pktgen_create_thread(int cpu) struct proc_dir_entry *pe; struct task_struct *p; - t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL); + t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, + cpu_to_node(cpu)); if (!t) { printk(KERN_ERR "pktgen: ERROR: out of memory, can't " "create new thread.\n"); -- cgit v1.2.3 From f64f9e719261a87818dd192a3a2352e5b20fbd0f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 29 Nov 2009 16:55:45 -0800 Subject: net: Move && and || to end of previous line Not including net/atm/ Compiled tested x86 allyesconfig only Added a > 80 column line or two, which I ignored. Existing checkpatch plaints willfully, cheerfully ignored. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/9p/trans_fd.c | 4 ++-- net/bluetooth/l2cap.c | 20 ++++++++++---------- net/bridge/br_fdb.c | 4 ++-- net/bridge/br_sysfs_br.c | 6 +++--- net/bridge/netfilter/ebt_stp.c | 4 ++-- net/can/af_can.c | 8 ++++---- net/core/dev.c | 7 ++++--- net/core/pktgen.c | 5 ++--- net/dcb/dcbnl.c | 4 ++-- net/decnet/dn_table.c | 5 +++-- net/ipv4/igmp.c | 5 +++-- net/ipv4/netfilter.c | 8 ++++---- net/irda/irnet/irnet_irda.c | 4 ++-- net/mac80211/agg-rx.c | 6 +++--- net/mac80211/main.c | 4 ++-- net/mac80211/mesh.c | 4 ++-- net/mac80211/mesh_hwmp.c | 15 +++++++-------- net/mac80211/rx.c | 4 ++-- net/mac80211/tx.c | 9 +++++---- net/netfilter/nf_conntrack_expect.c | 6 +++--- net/netfilter/nf_conntrack_ftp.c | 8 ++++---- net/packet/af_packet.c | 7 ++++--- net/phonet/pep.c | 4 ++-- net/phonet/socket.c | 4 ++-- net/rds/af_rds.c | 8 ++++---- net/rds/connection.c | 6 ++---- net/rds/ib_cm.c | 4 ++-- net/rds/ib_rdma.c | 4 ++-- net/rds/ib_recv.c | 12 ++++++------ net/rds/ib_send.c | 4 ++-- net/rds/iw_rdma.c | 4 ++-- net/rds/iw_recv.c | 12 ++++++------ net/rds/iw_send.c | 7 +++---- net/rds/message.c | 3 +-- net/rds/rdma.c | 12 ++++++------ net/rds/recv.c | 11 +++++------ net/rds/send.c | 27 +++++++++++++-------------- net/rds/threads.c | 4 ++-- net/rose/rose_route.c | 10 ++++++---- net/sched/cls_rsvp.h | 28 +++++++++++++++------------- net/sched/sch_htb.c | 4 ++-- net/sched/sch_netem.c | 12 ++++++------ net/sched/sch_teql.c | 11 +++++++---- net/sctp/outqueue.c | 4 ++-- net/sctp/socket.c | 4 ++-- net/sunrpc/auth.c | 6 +++--- net/sunrpc/auth_gss/gss_krb5_seqnum.c | 4 ++-- net/sunrpc/auth_gss/svcauth_gss.c | 4 ++-- net/sunrpc/cache.c | 5 ++--- net/sunrpc/svc.c | 5 +++-- net/sunrpc/svc_xprt.c | 8 ++++---- net/sunrpc/svcauth.c | 4 ++-- net/sunrpc/svcauth_unix.c | 4 ++-- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 7 +++---- net/sunrpc/xprtrdma/verbs.c | 4 ++-- net/tipc/cluster.c | 16 ++++++++-------- net/tipc/link.c | 12 ++++++------ net/tipc/socket.c | 12 +++++------- net/tipc/subscr.c | 6 +++--- net/unix/af_unix.c | 8 ++++---- net/wimax/op-rfkill.c | 8 ++++---- net/wireless/scan.c | 4 ++-- net/wireless/wext-core.c | 5 +++-- 63 files changed, 235 insertions(+), 233 deletions(-) (limited to 'net') diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 8d934dd7fd5..4dd873e3a1b 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -633,8 +633,8 @@ static void p9_poll_mux(struct p9_conn *m) if (n & POLLOUT) { set_bit(Wpending, &m->wsched); P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); - if ((m->wsize || !list_empty(&m->unsent_req_list)) - && !test_and_set_bit(Wworksched, &m->wsched)) { + if ((m->wsize || !list_empty(&m->unsent_req_list)) && + !test_and_set_bit(Wworksched, &m->wsched)) { P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); queue_work(p9_mux_wq, &m->wq); } diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 80d929842f0..54992f78230 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1362,8 +1362,8 @@ static int l2cap_ertm_send(struct sock *sk) if (pi->conn_state & L2CAP_CONN_WAIT_F) return 0; - while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) - && !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) { + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) && + !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) { tx_skb = skb_clone(skb, GFP_ATOMIC); if (pi->remote_max_tx && @@ -1604,8 +1604,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms return -EOPNOTSUPP; /* Check outgoing MTU */ - if (sk->sk_type == SOCK_SEQPACKET && pi->mode == L2CAP_MODE_BASIC - && len > pi->omtu) + if (sk->sk_type == SOCK_SEQPACKET && pi->mode == L2CAP_MODE_BASIC && + len > pi->omtu) return -EINVAL; lock_sock(sk); @@ -2756,8 +2756,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto unlock; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) - || l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) || + l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; sk->sk_state = BT_CONNECTED; @@ -2845,8 +2845,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) - || l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) || + l2cap_pi(sk)->fcs != L2CAP_FCS_NONE) l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; sk->sk_state = BT_CONNECTED; @@ -3388,8 +3388,8 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) - && (pi->unacked_frames > 0)) + if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (pi->unacked_frames > 0)) __mod_retrans_timer(); l2cap_ertm_send(sk); diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 57bf05c353b..3b8e038ab32 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -60,8 +60,8 @@ static inline unsigned long hold_time(const struct net_bridge *br) static inline int has_expired(const struct net_bridge *br, const struct net_bridge_fdb_entry *fdb) { - return !fdb->is_static - && time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); + return !fdb->is_static && + time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); } static inline int br_mac_hash(const unsigned char *mac) diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index ee4820aa184..bee4f300d0c 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -316,9 +316,9 @@ static ssize_t store_group_addr(struct device *d, if (new_addr[5] & ~0xf) return -EINVAL; - if (new_addr[5] == 1 /* 802.3x Pause address */ - || new_addr[5] == 2 /* 802.3ad Slow protocols */ - || new_addr[5] == 3) /* 802.1X PAE address */ + if (new_addr[5] == 1 || /* 802.3x Pause address */ + new_addr[5] == 2 || /* 802.3ad Slow protocols */ + new_addr[5] == 3) /* 802.1X PAE address */ return -EINVAL; spin_lock_bh(&br->lock); diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c index 48527e62162..75e29a9cebd 100644 --- a/net/bridge/netfilter/ebt_stp.c +++ b/net/bridge/netfilter/ebt_stp.c @@ -135,8 +135,8 @@ ebt_stp_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (memcmp(sp, header, sizeof(header))) return false; - if (info->bitmask & EBT_STP_TYPE - && FWINV(info->type != sp->type, EBT_STP_TYPE)) + if (info->bitmask & EBT_STP_TYPE && + FWINV(info->type != sp->type, EBT_STP_TYPE)) return false; if (sp->type == BPDU_TYPE_CONFIG && diff --git a/net/can/af_can.c b/net/can/af_can.c index f3067172886..51adc4c2b86 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -375,8 +375,8 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, return &d->rx[RX_ALL]; /* extra filterlists for the subscription of a single non-RTR can_id */ - if (((*mask & CAN_EFF_RTR_FLAGS) == CAN_EFF_RTR_FLAGS) - && !(*can_id & CAN_RTR_FLAG)) { + if (((*mask & CAN_EFF_RTR_FLAGS) == CAN_EFF_RTR_FLAGS) && + !(*can_id & CAN_RTR_FLAG)) { if (*can_id & CAN_EFF_FLAG) { if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) { @@ -525,8 +525,8 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, */ hlist_for_each_entry_rcu(r, next, rl, list) { - if (r->can_id == can_id && r->mask == mask - && r->func == func && r->data == data) + if (r->can_id == can_id && r->mask == mask && + r->func == func && r->data == data) break; } diff --git a/net/core/dev.c b/net/core/dev.c index 7775e8b48de..5d131c2f84c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2677,9 +2677,10 @@ __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) return GRO_NORMAL; for (p = napi->gro_list; p; p = p->next) { - NAPI_GRO_CB(p)->same_flow = (p->dev == skb->dev) - && !compare_ether_header(skb_mac_header(p), - skb_gro_mac_header(skb)); + NAPI_GRO_CB(p)->same_flow = + (p->dev == skb->dev) && + !compare_ether_header(skb_mac_header(p), + skb_gro_mac_header(skb)); NAPI_GRO_CB(p)->flush = 0; } diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 19ee493ec17..a23b45f08ec 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2052,9 +2052,8 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) read_lock_bh(&idev->lock); for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { - if (ifp->scope == IFA_LINK - && !(ifp-> - flags & IFA_F_TENTATIVE)) { + if (ifp->scope == IFA_LINK && + !(ifp->flags & IFA_F_TENTATIVE)) { ipv6_addr_copy(&pkt_dev-> cur_in6_saddr, &ifp->addr); diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 2afd617104d..db9f5b39388 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -1085,8 +1085,8 @@ static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, u8 value_byte; u32 value_int; - if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg - || !netdev->dcbnl_ops->setbcnrp) + if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg || + !netdev->dcbnl_ops->setbcnrp) return ret; ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index f281e0f59b0..b9a33bb5e9c 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -581,8 +581,9 @@ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct DN_FIB_SCAN_KEY(f, fp, key) { if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority) break; - if (f->fn_type == type && f->fn_scope == r->rtm_scope - && DN_FIB_INFO(f) == fi) + if (f->fn_type == type && + f->fn_scope == r->rtm_scope && + DN_FIB_INFO(f) == fi) goto out; } diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 6110c6d6e61..76c08402c93 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1899,8 +1899,9 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct err = -EADDRNOTAVAIL; for (pmc=inet->mc_list; pmc; pmc=pmc->next) { - if (pmc->multi.imr_multiaddr.s_addr == imr.imr_multiaddr.s_addr - && pmc->multi.imr_ifindex == imr.imr_ifindex) + if ((pmc->multi.imr_multiaddr.s_addr == + imr.imr_multiaddr.s_addr) && + (pmc->multi.imr_ifindex == imr.imr_ifindex)) break; } if (!pmc) { /* must have a prior join */ diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 1725dc0ef68..f53cb8df418 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -155,10 +155,10 @@ static int nf_ip_reroute(struct sk_buff *skb, if (entry->hook == NF_INET_LOCAL_OUT) { const struct iphdr *iph = ip_hdr(skb); - if (!(iph->tos == rt_info->tos - && skb->mark == rt_info->mark - && iph->daddr == rt_info->daddr - && iph->saddr == rt_info->saddr)) + if (!(iph->tos == rt_info->tos && + skb->mark == rt_info->mark && + iph->daddr == rt_info->daddr && + iph->saddr == rt_info->saddr)) return ip_route_me_harder(skb, RTN_UNSPEC); } return 0; diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c index cccc2e93234..b26dee784ab 100644 --- a/net/irda/irnet/irnet_irda.c +++ b/net/irda/irnet/irnet_irda.c @@ -1403,8 +1403,8 @@ irnet_connect_indication(void * instance, /* Socket already connecting ? On primary ? */ if(0 #ifdef ALLOW_SIMULT_CONNECT - || ((irttp_is_primary(server->tsap) == 1) /* primary */ - && (test_and_clear_bit(0, &new->ttp_connect))) + || ((irttp_is_primary(server->tsap) == 1) && /* primary */ + (test_and_clear_bit(0, &new->ttp_connect))) #endif /* ALLOW_SIMULT_CONNECT */ ) { diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 7ed5fe66473..614c65d62ae 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -211,9 +211,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, * check if configuration can support the BA policy * and if buffer size does not exceeds max value */ /* XXX: check own ht delayed BA capability?? */ - if (((ba_policy != 1) - && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) - || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { + if (((ba_policy != 1) && + (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) || + (buf_size > IEEE80211_MAX_AMPDU_BUF)) { status = WLAN_STATUS_INVALID_QOS_PARAM; #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index dd8ec8d5e8b..8116d1a96a4 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -631,8 +631,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) sta_info_stop(local); rate_control_deinitialize(local); - if (skb_queue_len(&local->skb_queue) - || skb_queue_len(&local->skb_queue_unreliable)) + if (skb_queue_len(&local->skb_queue) || + skb_queue_len(&local->skb_queue_unreliable)) printk(KERN_WARNING "%s: skb_queue not empty\n", wiphy_name(local->hw.wiphy)); skb_queue_purge(&local->skb_queue); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 51adb111521..c0fe46493f7 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -195,8 +195,8 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, list_del(&p->list); kmem_cache_free(rm_cache, p); --entries; - } else if ((seqnum == p->seqnum) - && (memcmp(sa, p->sa, ETH_ALEN) == 0)) + } else if ((seqnum == p->seqnum) && + (memcmp(sa, p->sa, ETH_ALEN) == 0)) return -1; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 9aecf0207af..833b2f3670c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -936,17 +936,16 @@ int mesh_nexthop_lookup(struct sk_buff *skb, } if (mpath->flags & MESH_PATH_ACTIVE) { - if (time_after(jiffies, mpath->exp_time + - msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) - && !memcmp(sdata->dev->dev_addr, hdr->addr4, - ETH_ALEN) - && !(mpath->flags & MESH_PATH_RESOLVING) - && !(mpath->flags & MESH_PATH_FIXED)) { + if (time_after(jiffies, + mpath->exp_time + + msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && + !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) && + !(mpath->flags & MESH_PATH_RESOLVING) && + !(mpath->flags & MESH_PATH_FIXED)) { mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); } - memcpy(hdr->addr1, mpath->next_hop->sta.addr, - ETH_ALEN); + memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN); } else { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!(mpath->flags & MESH_PATH_RESOLVING)) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 96f13ad05d3..beecf50fbd1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1168,8 +1168,8 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) rx->key)) return -EACCES; /* BIP does not use Protected field, so need to check MMIE */ - if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) - && ieee80211_get_mmie_keyidx(rx->skb) < 0 && + if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && + ieee80211_get_mmie_keyidx(rx->skb) < 0 && rx->key)) return -EACCES; /* diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 943def2b07d..8834cc93c71 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -366,10 +366,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; u32 staflags; - if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control) - || ieee80211_is_auth(hdr->frame_control) - || ieee80211_is_assoc_resp(hdr->frame_control) - || ieee80211_is_reassoc_resp(hdr->frame_control))) + if (unlikely(!sta || + ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_auth(hdr->frame_control) || + ieee80211_is_assoc_resp(hdr->frame_control) || + ieee80211_is_reassoc_resp(hdr->frame_control))) return TX_CONTINUE; staflags = get_sta_flags(sta); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 2032dfe25ca..fdf5d2a1d9b 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -202,9 +202,9 @@ static inline int expect_clash(const struct nf_conntrack_expect *a, static inline int expect_matches(const struct nf_conntrack_expect *a, const struct nf_conntrack_expect *b) { - return a->master == b->master && a->class == b->class - && nf_ct_tuple_equal(&a->tuple, &b->tuple) - && nf_ct_tuple_mask_equal(&a->mask, &b->mask); + return a->master == b->master && a->class == b->class && + nf_ct_tuple_equal(&a->tuple, &b->tuple) && + nf_ct_tuple_mask_equal(&a->mask, &b->mask); } /* Generally a bad idea to call this: could have matched already. */ diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 5509dd1f14c..38ea7ef3ccd 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -243,8 +243,8 @@ static int try_epsv_response(const char *data, size_t dlen, /* Three delimiters. */ if (dlen <= 3) return 0; delim = data[0]; - if (isdigit(delim) || delim < 33 || delim > 126 - || data[1] != delim || data[2] != delim) + if (isdigit(delim) || delim < 33 || delim > 126 || + data[1] != delim || data[2] != delim) return 0; return get_port(data, 3, dlen, delim, &cmd->u.tcp.port); @@ -366,8 +366,8 @@ static int help(struct sk_buff *skb, typeof(nf_nat_ftp_hook) nf_nat_ftp; /* Until there's been traffic both ways, don't look in packets. */ - if (ctinfo != IP_CT_ESTABLISHED - && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { pr_debug("ftp: Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 940fc20b2b5..020562164b5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1034,9 +1034,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) goto out_xmit; packet_increment_head(&po->tx_ring); len_sum += tp_len; - } while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT)) - && (atomic_read(&po->tx_ring.pending)))) - ); + } while (likely((ph != NULL) || + ((!(msg->msg_flags & MSG_DONTWAIT)) && + (atomic_read(&po->tx_ring.pending)))) + ); err = len_sum; goto out_put; diff --git a/net/phonet/pep.c b/net/phonet/pep.c index bdc17bdad36..b6356f3832f 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -714,8 +714,8 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) return -EINVAL; lock_sock(sk); - if (sock_flag(sk, SOCK_URGINLINE) - && !skb_queue_empty(&pn->ctrlreq_queue)) + if (sock_flag(sk, SOCK_URGINLINE) && + !skb_queue_empty(&pn->ctrlreq_queue)) answ = skb_peek(&pn->ctrlreq_queue)->len; else if (!skb_queue_empty(&sk->sk_receive_queue)) answ = skb_peek(&sk->sk_receive_queue)->len; diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 4112b6e1c48..69c8b826a0c 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -98,8 +98,8 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) if (pn->resource != res) continue; } - if (pn_addr(pn->sobject) - && pn_addr(pn->sobject) != pn_addr(obj)) + if (pn_addr(pn->sobject) && + pn_addr(pn->sobject) != pn_addr(obj)) continue; rval = sknode; diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index e25d8d5ce8d..853c52be781 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -174,8 +174,8 @@ static unsigned int rds_poll(struct file *file, struct socket *sock, mask |= (POLLIN | POLLRDNORM); spin_unlock(&rs->rs_lock); } - if (!list_empty(&rs->rs_recv_queue) - || !list_empty(&rs->rs_notify_queue)) + if (!list_empty(&rs->rs_recv_queue) || + !list_empty(&rs->rs_notify_queue)) mask |= (POLLIN | POLLRDNORM); if (rs->rs_snd_bytes < rds_sk_sndbuf(rs)) mask |= (POLLOUT | POLLWRNORM); @@ -308,8 +308,8 @@ static int rds_getsockopt(struct socket *sock, int level, int optname, if (len < sizeof(int)) ret = -EINVAL; else - if (put_user(rs->rs_recverr, (int __user *) optval) - || put_user(sizeof(int), optlen)) + if (put_user(rs->rs_recverr, (int __user *) optval) || + put_user(sizeof(int), optlen)) ret = -EFAULT; else ret = 0; diff --git a/net/rds/connection.c b/net/rds/connection.c index cc8b568c0c8..278f607ab60 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -133,10 +133,8 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, spin_lock_irqsave(&rds_conn_lock, flags); conn = rds_conn_lookup(head, laddr, faddr, trans); - if (conn - && conn->c_loopback - && conn->c_trans != &rds_loop_transport - && !is_outgoing) { + if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport && + !is_outgoing) { /* This is a looped back IB connection, and we're * called by the code handling the incoming connect. * We need a second connection object into which we diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 9d320692a4f..647cb8ffc39 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -377,8 +377,8 @@ static u32 rds_ib_protocol_compatible(struct rdma_cm_event *event) } /* Even if len is crap *now* I still want to check it. -ASG */ - if (event->param.conn.private_data_len < sizeof (*dp) - || dp->dp_protocol_major == 0) + if (event->param.conn.private_data_len < sizeof (*dp) || + dp->dp_protocol_major == 0) return RDS_PROTOCOL_3_0; common = be16_to_cpu(dp->dp_protocol_minor_mask) & RDS_IB_SUPPORTED_PROTOCOLS; diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index c5e916598c1..4b0da865a72 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -570,8 +570,8 @@ void rds_ib_free_mr(void *trans_private, int invalidate) spin_unlock_irqrestore(&pool->list_lock, flags); /* If we've pinned too many pages, request a flush */ - if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned - || atomic_read(&pool->dirty_count) >= pool->max_items / 10) + if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned || + atomic_read(&pool->dirty_count) >= pool->max_items / 10) queue_work(rds_wq, &pool->flush_worker); if (invalidate) { diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index fe5ab8c6b96..04dc0d3f3c9 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -230,8 +230,8 @@ int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp, int ret = 0; u32 pos; - while ((prefill || rds_conn_up(conn)) - && rds_ib_ring_alloc(&ic->i_recv_ring, 1, &pos)) { + while ((prefill || rds_conn_up(conn)) && + rds_ib_ring_alloc(&ic->i_recv_ring, 1, &pos)) { if (pos >= ic->i_recv_ring.w_nr) { printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n", pos); @@ -771,10 +771,10 @@ static void rds_ib_process_recv(struct rds_connection *conn, hdr = &ibinc->ii_inc.i_hdr; /* We can't just use memcmp here; fragments of a * single message may carry different ACKs */ - if (hdr->h_sequence != ihdr->h_sequence - || hdr->h_len != ihdr->h_len - || hdr->h_sport != ihdr->h_sport - || hdr->h_dport != ihdr->h_dport) { + if (hdr->h_sequence != ihdr->h_sequence || + hdr->h_len != ihdr->h_len || + hdr->h_sport != ihdr->h_sport || + hdr->h_dport != ihdr->h_dport) { rds_ib_conn_error(conn, "fragment header mismatch; forcing reconnect\n"); return; diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index 23bf830db2d..a10fab6886d 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -252,8 +252,8 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context) rds_ib_ring_free(&ic->i_send_ring, completed); - if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) - || test_bit(0, &conn->c_map_queued)) + if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) || + test_bit(0, &conn->c_map_queued)) queue_delayed_work(rds_wq, &conn->c_send_w, 0); /* We expect errors as the qp is drained during shutdown */ diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c index b25d785e49f..9eda11cca95 100644 --- a/net/rds/iw_rdma.c +++ b/net/rds/iw_rdma.c @@ -573,8 +573,8 @@ void rds_iw_free_mr(void *trans_private, int invalidate) rds_iw_free_fastreg(pool, ibmr); /* If we've pinned too many pages, request a flush */ - if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned - || atomic_read(&pool->dirty_count) >= pool->max_items / 10) + if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned || + atomic_read(&pool->dirty_count) >= pool->max_items / 10) queue_work(rds_wq, &pool->flush_worker); if (invalidate) { diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 24fc53f0383..54af7d6b92d 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -230,8 +230,8 @@ int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp, int ret = 0; u32 pos; - while ((prefill || rds_conn_up(conn)) - && rds_iw_ring_alloc(&ic->i_recv_ring, 1, &pos)) { + while ((prefill || rds_conn_up(conn)) && + rds_iw_ring_alloc(&ic->i_recv_ring, 1, &pos)) { if (pos >= ic->i_recv_ring.w_nr) { printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n", pos); @@ -730,10 +730,10 @@ static void rds_iw_process_recv(struct rds_connection *conn, hdr = &iwinc->ii_inc.i_hdr; /* We can't just use memcmp here; fragments of a * single message may carry different ACKs */ - if (hdr->h_sequence != ihdr->h_sequence - || hdr->h_len != ihdr->h_len - || hdr->h_sport != ihdr->h_sport - || hdr->h_dport != ihdr->h_dport) { + if (hdr->h_sequence != ihdr->h_sequence || + hdr->h_len != ihdr->h_len || + hdr->h_sport != ihdr->h_sport || + hdr->h_dport != ihdr->h_dport) { rds_iw_conn_error(conn, "fragment header mismatch; forcing reconnect\n"); return; diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c index 1f5abe3cf2b..1379e9d66a7 100644 --- a/net/rds/iw_send.c +++ b/net/rds/iw_send.c @@ -288,8 +288,8 @@ void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context) rds_iw_ring_free(&ic->i_send_ring, completed); - if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) - || test_bit(0, &conn->c_map_queued)) + if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) || + test_bit(0, &conn->c_map_queued)) queue_delayed_work(rds_wq, &conn->c_send_w, 0); /* We expect errors as the qp is drained during shutdown */ @@ -519,8 +519,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm, BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header)); /* Fastreg support */ - if (rds_rdma_cookie_key(rm->m_rdma_cookie) - && !ic->i_fastreg_posted) { + if (rds_rdma_cookie_key(rm->m_rdma_cookie) && !ic->i_fastreg_posted) { ret = -EAGAIN; goto out; } diff --git a/net/rds/message.c b/net/rds/message.c index ca50a8ec974..73e600ffd87 100644 --- a/net/rds/message.c +++ b/net/rds/message.c @@ -122,8 +122,7 @@ int rds_message_add_extension(struct rds_header *hdr, if (hdr->h_exthdr[0] != RDS_EXTHDR_NONE) return 0; - if (type >= __RDS_EXTHDR_MAX - || len != rds_exthdr_size[type]) + if (type >= __RDS_EXTHDR_MAX || len != rds_exthdr_size[type]) return 0; if (ext_len >= RDS_HEADER_EXT_SPACE) diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 971b5a66845..4c64daa1f5d 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -631,8 +631,8 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, { struct rds_rdma_op *op; - if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args)) - || rm->m_rdma_op != NULL) + if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args)) || + rm->m_rdma_op != NULL) return -EINVAL; op = rds_rdma_prepare(rs, CMSG_DATA(cmsg)); @@ -655,8 +655,8 @@ int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm, u32 r_key; int err = 0; - if (cmsg->cmsg_len < CMSG_LEN(sizeof(rds_rdma_cookie_t)) - || rm->m_rdma_cookie != 0) + if (cmsg->cmsg_len < CMSG_LEN(sizeof(rds_rdma_cookie_t)) || + rm->m_rdma_cookie != 0) return -EINVAL; memcpy(&rm->m_rdma_cookie, CMSG_DATA(cmsg), sizeof(rm->m_rdma_cookie)); @@ -692,8 +692,8 @@ int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm, int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm, struct cmsghdr *cmsg) { - if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_get_mr_args)) - || rm->m_rdma_cookie != 0) + if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_get_mr_args)) || + rm->m_rdma_cookie != 0) return -EINVAL; return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie, &rm->m_rdma_mr); diff --git a/net/rds/recv.c b/net/rds/recv.c index fdff33c7b43..b426d67f760 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -195,8 +195,8 @@ void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr, * XXX we could spend more on the wire to get more robust failure * detection, arguably worth it to avoid data corruption. */ - if (be64_to_cpu(inc->i_hdr.h_sequence) < conn->c_next_rx_seq - && (inc->i_hdr.h_flags & RDS_FLAG_RETRANSMITTED)) { + if (be64_to_cpu(inc->i_hdr.h_sequence) < conn->c_next_rx_seq && + (inc->i_hdr.h_flags & RDS_FLAG_RETRANSMITTED)) { rds_stats_inc(s_recv_drop_old_seq); goto out; } @@ -432,10 +432,9 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, } timeo = wait_event_interruptible_timeout(*sk->sk_sleep, - (!list_empty(&rs->rs_notify_queue) - || rs->rs_cong_notify - || rds_next_incoming(rs, &inc)), - timeo); + (!list_empty(&rs->rs_notify_queue) || + rs->rs_cong_notify || + rds_next_incoming(rs, &inc)), timeo); rdsdebug("recvmsg woke inc %p timeo %ld\n", inc, timeo); if (timeo > 0 || timeo == MAX_SCHEDULE_TIMEOUT) diff --git a/net/rds/send.c b/net/rds/send.c index 28c88ff3d03..b2fccfc2076 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -235,8 +235,8 @@ int rds_send_xmit(struct rds_connection *conn) * connection. * Therefore, we never retransmit messages with RDMA ops. */ - if (rm->m_rdma_op - && test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags)) { + if (rm->m_rdma_op && + test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags)) { spin_lock_irqsave(&conn->c_lock, flags); if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags)) list_move(&rm->m_conn_item, &to_be_dropped); @@ -247,8 +247,8 @@ int rds_send_xmit(struct rds_connection *conn) /* Require an ACK every once in a while */ len = ntohl(rm->m_inc.i_hdr.h_len); - if (conn->c_unacked_packets == 0 - || conn->c_unacked_bytes < len) { + if (conn->c_unacked_packets == 0 || + conn->c_unacked_bytes < len) { __set_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags); conn->c_unacked_packets = rds_sysctl_max_unacked_packets; @@ -418,8 +418,8 @@ void rds_rdma_send_complete(struct rds_message *rm, int status) spin_lock(&rm->m_rs_lock); ro = rm->m_rdma_op; - if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags) - && ro && ro->r_notify && ro->r_notifier) { + if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags) && + ro && ro->r_notify && ro->r_notifier) { notifier = ro->r_notifier; rs = rm->m_rs; sock_hold(rds_rs_to_sk(rs)); @@ -549,8 +549,7 @@ void rds_send_remove_from_sock(struct list_head *messages, int status) list_del_init(&rm->m_sock_item); rds_send_sndbuf_remove(rs, rm); - if (ro && ro->r_notifier - && (status || ro->r_notify)) { + if (ro && ro->r_notifier && (status || ro->r_notify)) { notifier = ro->r_notifier; list_add_tail(¬ifier->n_list, &rs->rs_notify_queue); @@ -877,8 +876,8 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, if (ret) goto out; - if ((rm->m_rdma_cookie || rm->m_rdma_op) - && conn->c_trans->xmit_rdma == NULL) { + if ((rm->m_rdma_cookie || rm->m_rdma_op) && + conn->c_trans->xmit_rdma == NULL) { if (printk_ratelimit()) printk(KERN_NOTICE "rdma_op %p conn xmit_rdma %p\n", rm->m_rdma_op, conn->c_trans->xmit_rdma); @@ -890,8 +889,8 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, * have scheduled a delayed reconnect however - in this case * we should not interfere. */ - if (rds_conn_state(conn) == RDS_CONN_DOWN - && !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags)) + if (rds_conn_state(conn) == RDS_CONN_DOWN && + !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags)) queue_delayed_work(rds_wq, &conn->c_conn_w, 0); ret = rds_cong_wait(conn->c_fcong, dport, nonblock, rs); @@ -973,8 +972,8 @@ rds_send_pong(struct rds_connection *conn, __be16 dport) * have scheduled a delayed reconnect however - in this case * we should not interfere. */ - if (rds_conn_state(conn) == RDS_CONN_DOWN - && !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags)) + if (rds_conn_state(conn) == RDS_CONN_DOWN && + !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags)) queue_delayed_work(rds_wq, &conn->c_conn_w, 0); ret = rds_cong_wait(conn->c_fcong, dport, 1, NULL); diff --git a/net/rds/threads.c b/net/rds/threads.c index dd7e0cad1e7..00fa10e59af 100644 --- a/net/rds/threads.c +++ b/net/rds/threads.c @@ -170,8 +170,8 @@ void rds_shutdown_worker(struct work_struct *work) * handler is supposed to check for state DISCONNECTING */ mutex_lock(&conn->c_cm_lock); - if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING) - && !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) { + if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING) && + !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) { rds_conn_error(conn, "shutdown called in state %d\n", atomic_read(&conn->c_state)); mutex_unlock(&conn->c_cm_lock); diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index ea2e72337e2..795c4b025e3 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -77,8 +77,9 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, rose_neigh = rose_neigh_list; while (rose_neigh != NULL) { - if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 - && rose_neigh->dev == dev) + if (ax25cmp(&rose_route->neighbour, + &rose_neigh->callsign) == 0 && + rose_neigh->dev == dev) break; rose_neigh = rose_neigh->next; } @@ -311,8 +312,9 @@ static int rose_del_node(struct rose_route_struct *rose_route, rose_neigh = rose_neigh_list; while (rose_neigh != NULL) { - if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 - && rose_neigh->dev == dev) + if (ax25cmp(&rose_route->neighbour, + &rose_neigh->callsign) == 0 && + rose_neigh->dev == dev) break; rose_neigh = rose_neigh->next; } diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 7034ea4530e..dd9414e4420 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -170,21 +170,23 @@ restart: for (s = sht[h1]; s; s = s->next) { if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && protocol == s->protocol && - !(s->dpi.mask & (*(u32*)(xprt+s->dpi.offset)^s->dpi.key)) + !(s->dpi.mask & + (*(u32*)(xprt+s->dpi.offset)^s->dpi.key)) && #if RSVP_DST_LEN == 4 - && dst[0] == s->dst[0] - && dst[1] == s->dst[1] - && dst[2] == s->dst[2] + dst[0] == s->dst[0] && + dst[1] == s->dst[1] && + dst[2] == s->dst[2] && #endif - && tunnelid == s->tunnelid) { + tunnelid == s->tunnelid) { for (f = s->ht[h2]; f; f = f->next) { if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN-1] && !(f->spi.mask & (*(u32*)(xprt+f->spi.offset)^f->spi.key)) #if RSVP_DST_LEN == 4 - && src[0] == f->src[0] - && src[1] == f->src[1] - && src[2] == f->src[2] + && + src[0] == f->src[0] && + src[1] == f->src[1] && + src[2] == f->src[2] #endif ) { *res = f->res; @@ -493,13 +495,13 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, for (sp = &data->ht[h1]; (s=*sp) != NULL; sp = &s->next) { if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && pinfo && pinfo->protocol == s->protocol && - memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 + memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 && #if RSVP_DST_LEN == 4 - && dst[0] == s->dst[0] - && dst[1] == s->dst[1] - && dst[2] == s->dst[2] + dst[0] == s->dst[0] && + dst[1] == s->dst[1] && + dst[2] == s->dst[2] && #endif - && pinfo->tunnelid == s->tunnelid) { + pinfo->tunnelid == s->tunnelid) { insert: /* OK, we found appropriate session */ diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 2e38d1abd83..508cf5f3a6d 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1344,8 +1344,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, }; /* check for valid classid */ - if (!classid || TC_H_MAJ(classid ^ sch->handle) - || htb_find(classid, sch)) + if (!classid || TC_H_MAJ(classid ^ sch->handle) || + htb_find(classid, sch)) goto failure; /* check maximal depth */ diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 2b88295cb7b..d8b10e05462 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -199,9 +199,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) * do it now in software before we mangle it. */ if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) { - if (!(skb = skb_unshare(skb, GFP_ATOMIC)) - || (skb->ip_summed == CHECKSUM_PARTIAL - && skb_checksum_help(skb))) { + if (!(skb = skb_unshare(skb, GFP_ATOMIC)) || + (skb->ip_summed == CHECKSUM_PARTIAL && + skb_checksum_help(skb))) { sch->qstats.drops++; return NET_XMIT_DROP; } @@ -210,9 +210,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) } cb = netem_skb_cb(skb); - if (q->gap == 0 /* not doing reordering */ - || q->counter < q->gap /* inside last reordering gap */ - || q->reorder < get_crandom(&q->reorder_cor)) { + if (q->gap == 0 || /* not doing reordering */ + q->counter < q->gap || /* inside last reordering gap */ + q->reorder < get_crandom(&q->reorder_cor)) { psched_time_t now; psched_tdiff_t delay; diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 5a002c24723..db69637069c 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -190,10 +190,13 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) if (m->slaves) { if (m->dev->flags & IFF_UP) { - if ((m->dev->flags&IFF_POINTOPOINT && !(dev->flags&IFF_POINTOPOINT)) - || (m->dev->flags&IFF_BROADCAST && !(dev->flags&IFF_BROADCAST)) - || (m->dev->flags&IFF_MULTICAST && !(dev->flags&IFF_MULTICAST)) - || dev->mtu < m->dev->mtu) + if ((m->dev->flags & IFF_POINTOPOINT && + !(dev->flags & IFF_POINTOPOINT)) || + (m->dev->flags & IFF_BROADCAST && + !(dev->flags & IFF_BROADCAST)) || + (m->dev->flags & IFF_MULTICAST && + !(dev->flags & IFF_MULTICAST)) || + dev->mtu < m->dev->mtu) return -EINVAL; } else { if (!(dev->flags&IFF_POINTOPOINT)) diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index e231a983101..229690f02a1 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -191,8 +191,8 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary, __u32 tsn) { if (primary->cacc.changeover_active && - (sctp_cacc_skip_3_1(primary, transport, count_of_newacks) - || sctp_cacc_skip_3_2(primary, tsn))) + (sctp_cacc_skip_3_1(primary, transport, count_of_newacks) || + sctp_cacc_skip_3_2(primary, tsn))) return 1; return 0; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 71513b3926a..5fa9ac52e13 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2356,8 +2356,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, pmtud_change == SPP_PMTUD || sackdelay_change == SPP_SACKDELAY || params.spp_sackdelay > 500 || - (params.spp_pathmtu - && params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) + (params.spp_pathmtu && + params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT)) return -EINVAL; /* If an address other than INADDR_ANY is specified, and diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 54a4e042f10..7535a7bed2f 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -332,9 +332,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, list_add_tail(&new->cr_lru, &free); spin_unlock(&cache->lock); found: - if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) - && cred->cr_ops->cr_init != NULL - && !(flags & RPCAUTH_LOOKUP_NEW)) { + if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && + cred->cr_ops->cr_init != NULL && + !(flags & RPCAUTH_LOOKUP_NEW)) { int res = cred->cr_ops->cr_init(auth, cred); if (res < 0) { put_rpccred(cred); diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c index f160be6c1a4..17562b4c35f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c +++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c @@ -75,8 +75,8 @@ krb5_get_seq_num(struct crypto_blkcipher *key, if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) return code; - if ((plain[4] != plain[5]) || (plain[4] != plain[6]) - || (plain[4] != plain[7])) + if ((plain[4] != plain[5]) || (plain[4] != plain[6]) || + (plain[4] != plain[7])) return (s32)KG_BAD_SEQ; *direction = plain[4]; diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index f6c51e562a0..e34bc531fcb 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -105,8 +105,8 @@ static int rsi_match(struct cache_head *a, struct cache_head *b) { struct rsi *item = container_of(a, struct rsi, h); struct rsi *tmp = container_of(b, struct rsi, h); - return netobj_equal(&item->in_handle, &tmp->in_handle) - && netobj_equal(&item->in_token, &tmp->in_token); + return netobj_equal(&item->in_handle, &tmp->in_handle) && + netobj_equal(&item->in_token, &tmp->in_token); } static int dup_to_netobj(struct xdr_netobj *dst, char *src, int len) diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index d6eee291a0e..39bddba53ba 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -401,9 +401,8 @@ static int cache_clean(void) for (; ch; cp= & ch->next, ch= *cp) { if (current_detail->nextcheck > ch->expiry_time) current_detail->nextcheck = ch->expiry_time+1; - if (ch->expiry_time >= get_seconds() - && ch->last_refresh >= current_detail->flush_time - ) + if (ch->expiry_time >= get_seconds() && + ch->last_refresh >= current_detail->flush_time) continue; if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) cache_dequeue(current_detail, ch); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 952f206ff30..538ca433a56 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1103,8 +1103,9 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) procp->pc_release(rqstp, NULL, rqstp->rq_resp); goto dropit; } - if (*statp == rpc_success && (xdr = procp->pc_encode) - && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { + if (*statp == rpc_success && + (xdr = procp->pc_encode) && + !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { dprintk("svc: failed to encode reply\n"); /* serv->sv_stats->rpcsystemerr++; */ *statp = rpc_system_err; diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index df124f78ee4..b845e2293df 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -129,8 +129,8 @@ static void svc_xprt_free(struct kref *kref) struct svc_xprt *xprt = container_of(kref, struct svc_xprt, xpt_ref); struct module *owner = xprt->xpt_class->xcl_owner; - if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags) - && xprt->xpt_auth_cache != NULL) + if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags) && + xprt->xpt_auth_cache != NULL) svcauth_unix_info_release(xprt->xpt_auth_cache); xprt->xpt_ops->xpo_free(xprt); module_put(owner); @@ -846,8 +846,8 @@ static void svc_age_temp_xprts(unsigned long closure) * through, close it. */ if (!test_and_set_bit(XPT_OLD, &xprt->xpt_flags)) continue; - if (atomic_read(&xprt->xpt_ref.refcount) > 1 - || test_bit(XPT_BUSY, &xprt->xpt_flags)) + if (atomic_read(&xprt->xpt_ref.refcount) > 1 || + test_bit(XPT_BUSY, &xprt->xpt_flags)) continue; svc_xprt_get(xprt); list_move(le, &to_be_aged); diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index e64109b02ae..4e9393c2468 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c @@ -46,8 +46,8 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) dprintk("svc: svc_authenticate (%d)\n", flavor); spin_lock(&authtab_lock); - if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor]) - || !try_module_get(aops->owner)) { + if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor]) || + !try_module_get(aops->owner)) { spin_unlock(&authtab_lock); *authp = rpc_autherr_badcred; return SVC_DENIED; diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index f4c7ff3a53e..4a8f6558718 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -125,8 +125,8 @@ static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) { struct ip_map *orig = container_of(corig, struct ip_map, h); struct ip_map *new = container_of(cnew, struct ip_map, h); - return strcmp(orig->m_class, new->m_class) == 0 - && ipv6_addr_equal(&orig->m_addr, &new->m_addr); + return strcmp(orig->m_class, new->m_class) == 0 && + ipv6_addr_equal(&orig->m_addr, &new->m_addr); } static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) { diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 9e884383134..f92e37eb413 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -337,10 +337,9 @@ static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt, static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count) { - if ((RDMA_TRANSPORT_IWARP == - rdma_node_get_transport(xprt->sc_cm_id-> - device->node_type)) - && sge_count > 1) + if ((rdma_node_get_transport(xprt->sc_cm_id->device->node_type) == + RDMA_TRANSPORT_IWARP) && + sge_count > 1) return 1; else return min_t(int, sge_count, xprt->sc_max_sge); diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 465aafc2007..2209aa87d89 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -878,8 +878,8 @@ if (strnicmp(ia->ri_id->device->dma_device->bus->name, "pci", 3) == 0) { * others indicate a transport condition which has already * undergone a best-effort. */ - if (ep->rep_connected == -ECONNREFUSED - && ++retry_count <= RDMA_CONNECT_RETRY_MAX) { + if (ep->rep_connected == -ECONNREFUSED && + ++retry_count <= RDMA_CONNECT_RETRY_MAX) { dprintk("RPC: %s: non-peer_reject, retry\n", __func__); goto retry; } diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c index 689fdefe9d0..a7eac00cd36 100644 --- a/net/tipc/cluster.c +++ b/net/tipc/cluster.c @@ -437,11 +437,11 @@ void tipc_cltr_recv_routing_table(struct sk_buff *buf) break; case ROUTE_ADDITION: if (!is_slave(tipc_own_addr)) { - assert(!in_own_cluster(c_ptr->addr) - || is_slave(rem_node)); + assert(!in_own_cluster(c_ptr->addr) || + is_slave(rem_node)); } else { - assert(in_own_cluster(c_ptr->addr) - && !is_slave(rem_node)); + assert(in_own_cluster(c_ptr->addr) && + !is_slave(rem_node)); } n_ptr = c_ptr->nodes[tipc_node(rem_node)]; if (!n_ptr) @@ -451,11 +451,11 @@ void tipc_cltr_recv_routing_table(struct sk_buff *buf) break; case ROUTE_REMOVAL: if (!is_slave(tipc_own_addr)) { - assert(!in_own_cluster(c_ptr->addr) - || is_slave(rem_node)); + assert(!in_own_cluster(c_ptr->addr) || + is_slave(rem_node)); } else { - assert(in_own_cluster(c_ptr->addr) - && !is_slave(rem_node)); + assert(in_own_cluster(c_ptr->addr) && + !is_slave(rem_node)); } n_ptr = c_ptr->nodes[tipc_node(rem_node)]; if (n_ptr) diff --git a/net/tipc/link.c b/net/tipc/link.c index dd4c18b9a35..6f50f6423f6 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -378,8 +378,8 @@ static void link_timeout(struct link *l_ptr) struct tipc_msg *msg = buf_msg(l_ptr->first_out); u32 length = msg_size(msg); - if ((msg_user(msg) == MSG_FRAGMENTER) - && (msg_type(msg) == FIRST_FRAGMENT)) { + if ((msg_user(msg) == MSG_FRAGMENTER) && + (msg_type(msg) == FIRST_FRAGMENT)) { length = msg_size(msg_get_wrapped(msg)); } if (length) { @@ -2788,8 +2788,8 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, /* Is there an incomplete message waiting for this fragment? */ - while (pbuf && ((msg_seqno(buf_msg(pbuf)) != long_msg_seq_no) - || (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) { + while (pbuf && ((msg_seqno(buf_msg(pbuf)) != long_msg_seq_no) || + (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) { prev = pbuf; pbuf = pbuf->next; } @@ -3325,8 +3325,8 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, (l_ptr->last_out)), l_ptr->out_queue_size); if ((mod(msg_seqno(buf_msg(l_ptr->last_out)) - msg_seqno(buf_msg(l_ptr->first_out))) - != (l_ptr->out_queue_size - 1)) - || (l_ptr->last_out->next != NULL)) { + != (l_ptr->out_queue_size - 1)) || + (l_ptr->last_out->next != NULL)) { tipc_printf(buf, "\nSend queue inconsistency\n"); tipc_printf(buf, "first_out= %x ", l_ptr->first_out); tipc_printf(buf, "next_out= %x ", l_ptr->next_out); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index eca5eb0dab0..1ea64f09cc4 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1136,13 +1136,11 @@ restart: /* Loop around if more data is required */ - if ((sz_copied < buf_len) /* didn't get all requested data */ - && (!skb_queue_empty(&sk->sk_receive_queue) || - (flags & MSG_WAITALL)) - /* ... and more is ready or required */ - && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */ - && (!err) /* ... and haven't reached a FIN */ - ) + if ((sz_copied < buf_len) && /* didn't get all requested data */ + (!skb_queue_empty(&sk->sk_receive_queue) || + (flags & MSG_WAITALL)) && /* and more is ready or required */ + (!(flags & MSG_PEEK)) && /* and aren't just peeking at data */ + (!err)) /* and haven't reached a FIN */ goto restart; exit: diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 0747d8a9232..ac91f0dfa14 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -364,9 +364,9 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s, sub->seq.upper = htohl(s->seq.upper, swap); sub->timeout = htohl(s->timeout, swap); sub->filter = htohl(s->filter, swap); - if ((!(sub->filter & TIPC_SUB_PORTS) - == !(sub->filter & TIPC_SUB_SERVICE)) - || (sub->seq.lower > sub->seq.upper)) { + if ((!(sub->filter & TIPC_SUB_PORTS) == + !(sub->filter & TIPC_SUB_SERVICE)) || + (sub->seq.lower > sub->seq.upper)) { warn("Subscription rejected, illegal request\n"); kfree(sub); subscr_terminate(subscriber); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 7553ea6edd8..f2551190311 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1033,8 +1033,8 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, goto out; addr_len = err; - if (test_bit(SOCK_PASSCRED, &sock->flags) - && !u->addr && (err = unix_autobind(sock)) != 0) + if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr && + (err = unix_autobind(sock)) != 0) goto out; timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); @@ -1378,8 +1378,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; } - if (test_bit(SOCK_PASSCRED, &sock->flags) - && !u->addr && (err = unix_autobind(sock)) != 0) + if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr + && (err = unix_autobind(sock)) != 0) goto out; err = -EMSGSIZE; diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 94d339c345d..ae752a64d92 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -107,8 +107,8 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, if (state != wimax_dev->rf_hw) { wimax_dev->rf_hw = state; - if (wimax_dev->rf_hw == WIMAX_RF_ON - && wimax_dev->rf_sw == WIMAX_RF_ON) + if (wimax_dev->rf_hw == WIMAX_RF_ON && + wimax_dev->rf_sw == WIMAX_RF_ON) wimax_state = WIMAX_ST_READY; else wimax_state = WIMAX_ST_RADIO_OFF; @@ -163,8 +163,8 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, if (state != wimax_dev->rf_sw) { wimax_dev->rf_sw = state; - if (wimax_dev->rf_hw == WIMAX_RF_ON - && wimax_dev->rf_sw == WIMAX_RF_ON) + if (wimax_dev->rf_hw == WIMAX_RF_ON && + wimax_dev->rf_sw == WIMAX_RF_ON) wimax_state = WIMAX_ST_READY; else wimax_state = WIMAX_ST_RADIO_OFF; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 227d57b8dc4..96df34c3c6e 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -937,8 +937,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, ie += ie[1] + 2; } - if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) - || ismesh) { + if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) || + ismesh) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; if (ismesh) diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index a4e5ddc8d4f..58dfb954974 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -911,8 +911,9 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, */ static int wext_permission_check(unsigned int cmd) { - if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) - && !capable(CAP_NET_ADMIN)) + if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || + cmd == SIOCGIWENCODEEXT) && + !capable(CAP_NET_ADMIN)) return -EPERM; return 0; -- cgit v1.2.3 From 1fdf475aa141a669af8db6ccc7015f0b725087de Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 30 Nov 2009 12:53:30 -0800 Subject: tcp: tcp_disconnect() should clear window_clamp NFS can reuse its TCP socket after calling tcp_disconnect(). We noticed window scaling was not negotiated in SYN packet of next connection request. Fix is to clear tp->window_clamp in tcp_disconnect(). Reported-by: Krzysztof Oledzki Tested-by: Krzysztof Oledzki Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f1813bc7108..d7a884c534a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2059,6 +2059,7 @@ int tcp_disconnect(struct sock *sk, int flags) tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_cnt = 0; tp->bytes_acked = 0; + tp->window_clamp = 0; tcp_set_ca_state(sk, TCP_CA_Open); tcp_clear_retrans(tp); inet_csk_delack_init(sk); -- cgit v1.2.3 From 138f3c8518976953563a1316d7e0420c72d4ab96 Mon Sep 17 00:00:00 2001 From: Li Yewang Date: Tue, 1 Dec 2009 15:35:05 -0800 Subject: ipsec: can not add camellia cipher algorithm when using "ip xfrm state" command can not add camellia cipher algorithm when using "ip xfrm state" command. Signed-off-by: Li Yewang Signed-off-by: David S. Miller --- net/xfrm/xfrm_algo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index faf54c6bf96..348196df81e 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -365,6 +365,7 @@ static struct xfrm_algo_desc ealg_list[] = { }, { .name = "cbc(camellia)", + .compat = "camellia", .uinfo = { .encr = { -- cgit v1.2.3 From b2722b1c3a893ec6021508da15b32282ec79f4da Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 1 Dec 2009 15:53:57 -0800 Subject: ip_fragment: also adjust skb->truesize for packets not owned by a socket When a large packet gets reassembled by ip_defrag(), the head skb accounts for all the fragments in skb->truesize. If this packet is refragmented again, skb->truesize is not re-adjusted to reflect only the head size since its not owned by a socket. If the head fragment then gets recycled and reused for another received fragment, it might exceed the defragmentation limits due to its large truesize value. skb_recycle_check() explicitly checks for linear skbs, so any recycled skb should reflect its true size in skb->truesize. Change ip_fragment() to also adjust the truesize value of skbs not owned by a socket. Reported-and-tested-by: Ben Menchaca Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index f9895180f48..4d50daab0c3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -501,8 +501,8 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) if (skb->sk) { frag->sk = skb->sk; frag->destructor = sock_wfree; - truesizes += frag->truesize; } + truesizes += frag->truesize; } /* Everything is OK. Generate! */ -- cgit v1.2.3 From a5ee155136b4a8f4ab0e4c9c064b661da475e298 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:45:58 +0000 Subject: net: NETDEV_UNREGISTER_PERNET -> NETDEV_UNREGISTER_BATCH The motivation for an additional notifier in batched netdevice notification (rt_do_flush) only needs to be called once per batch not once per namespace. For further batching improvements I need a guarantee that the netdevices are unregistered in order allowing me to unregister an all of the network devices in a network namespace at the same time with the guarantee that the loopback device is really and truly unregistered last. Additionally it appears that we moved the route cache flush after the final synchronize_net, which seems wrong and there was no explanation. So I have restored the original location of the final synchronize_net. Cc: Octavian Purdila Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/linux/notifier.h | 2 +- include/net/route.h | 1 + net/core/dev.c | 36 +++++++++--------------------------- net/ipv4/fib_frontend.c | 4 +++- net/ipv4/route.c | 6 ++++++ 5 files changed, 20 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/include/linux/notifier.h b/include/linux/notifier.h index b0c3671d463..fee6c2f6807 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -202,7 +202,7 @@ static inline int notifier_to_errno(int ret) #define NETDEV_BONDING_OLDTYPE 0x000E #define NETDEV_BONDING_NEWTYPE 0x000F #define NETDEV_POST_INIT 0x0010 -#define NETDEV_UNREGISTER_PERNET 0x0011 +#define NETDEV_UNREGISTER_BATCH 0x0011 #define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_RESTART SYS_DOWN diff --git a/include/net/route.h b/include/net/route.h index cfb4c071a13..bce6dd68d27 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -108,6 +108,7 @@ extern int ip_rt_init(void); extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw, __be32 src, struct net_device *dev); extern void rt_cache_flush(struct net *net, int how); +extern void rt_cache_flush_batch(void); extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp); extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp); extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags); diff --git a/net/core/dev.c b/net/core/dev.c index 5d131c2f84c..bb37ee1e090 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1353,7 +1353,7 @@ rollback: nb->notifier_call(nb, NETDEV_DOWN, dev); } nb->notifier_call(nb, NETDEV_UNREGISTER, dev); - nb->notifier_call(nb, NETDEV_UNREGISTER_PERNET, dev); + nb->notifier_call(nb, NETDEV_UNREGISTER_BATCH, dev); } } @@ -4771,8 +4771,7 @@ static void net_set_todo(struct net_device *dev) static void rollback_registered_many(struct list_head *head) { - struct net_device *dev, *aux, *fdev; - LIST_HEAD(pernet_list); + struct net_device *dev; BUG_ON(dev_boot_phase); ASSERT_RTNL(); @@ -4828,26 +4827,14 @@ static void rollback_registered_many(struct list_head *head) netdev_unregister_kobject(dev); } - synchronize_net(); + /* Process any work delayed until the end of the batch */ + dev = list_entry(head->next, struct net_device, unreg_list); + call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev); - list_for_each_entry_safe(dev, aux, head, unreg_list) { - int new_net = 1; - list_for_each_entry(fdev, &pernet_list, unreg_list) { - if (net_eq(dev_net(dev), dev_net(fdev))) { - new_net = 0; - dev_put(dev); - break; - } - } - if (new_net) - list_move(&dev->unreg_list, &pernet_list); - } + synchronize_net(); - list_for_each_entry_safe(dev, aux, &pernet_list, unreg_list) { - call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev); - list_move(&dev->unreg_list, head); + list_for_each_entry(dev, head, unreg_list) dev_put(dev); - } } static void rollback_registered(struct net_device *dev) @@ -5129,7 +5116,7 @@ static void netdev_wait_allrefs(struct net_device *dev) /* Rebroadcast unregister notification */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - /* don't resend NETDEV_UNREGISTER_PERNET, _PERNET users + /* don't resend NETDEV_UNREGISTER_BATCH, _BATCH users * should have already handle it the first time */ if (test_bit(__LINK_STATE_LINKWATCH_PENDING, @@ -5442,11 +5429,6 @@ EXPORT_SYMBOL(unregister_netdevice_queue); /** * unregister_netdevice_many - unregister many devices * @head: list of devices - * - * WARNING: Calling this modifies the given list - * (in rollback_registered_many). It may change the order of the elements - * in the list. However, you can assume it does not add or delete elements - * to/from the list. */ void unregister_netdevice_many(struct list_head *head) { @@ -5555,7 +5537,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char this device. They should clean all the things. */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev); + call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev); /* * Flush the unicast and multicast chains diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 6c1e56aef1f..3b373a8b047 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -959,9 +959,11 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo break; case NETDEV_CHANGEMTU: case NETDEV_CHANGE: - case NETDEV_UNREGISTER_PERNET: rt_cache_flush(dev_net(dev), 0); break; + case NETDEV_UNREGISTER_BATCH: + rt_cache_flush_batch(); + break; } return NOTIFY_DONE; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9889fbd9648..90cdcfc3293 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -900,6 +900,12 @@ void rt_cache_flush(struct net *net, int delay) rt_do_flush(!in_softirq()); } +/* Flush previous cache invalidated entries from the cache */ +void rt_cache_flush_batch(void) +{ + rt_do_flush(!in_softirq()); +} + /* * We change rt_genid and let gc do the cleanup */ -- cgit v1.2.3 From 2b035b39970740722598f7a9d548835f9bdd730f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 22:25:27 +0000 Subject: net: Batch network namespace destruction. It is fairly common to kill several network namespaces at once. Either because they are nested one inside the other or because they are cooperating in multiple machine networking experiments. As the network stack control logic does not parallelize easily batch up multiple network namespaces existing together. To get the full benefit of batching the virtual network devices to be removed must be all removed in one batch. For that purpose I have added a loop after the last network device operations have run that batches up all remaining network devices and deletes them. An extra benefit is that the reorganization slightly shrinks the size of the per network namespace data structures replaceing a work_struct with a list_head. In a trivial test with 4K namespaces this change reduced the cost of a destroying 4K namespaces from 7+ minutes (at 12% cpu) to 44 seconds (at 60% cpu). The bulk of that 44s was spent in inet_twsk_purge. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/net_namespace.h | 2 +- net/core/net_namespace.c | 66 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 0addd45038a..d69b4796030 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -42,7 +42,7 @@ struct net { */ #endif struct list_head list; /* list of network namespaces */ - struct work_struct work; /* work struct for freeing */ + struct list_head cleanup_list; /* namespaces on death row */ struct proc_dir_entry *proc_net; struct proc_dir_entry *proc_net_stat; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 86ed7f44d08..a42caa2b909 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -8,8 +8,10 @@ #include #include #include +#include #include #include +#include /* * Our network namespace constructor/destructor lists @@ -27,6 +29,20 @@ EXPORT_SYMBOL(init_net); #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ +static void unregister_netdevices(struct net *net, struct list_head *list) +{ + struct net_device *dev; + /* At exit all network devices most be removed from a network + * namespace. Do this in the reverse order of registeration. + */ + for_each_netdev_reverse(net, dev) { + if (dev->rtnl_link_ops) + dev->rtnl_link_ops->dellink(dev, list); + else + unregister_netdevice_queue(dev, list); + } +} + /* * setup_net runs the initializers for the network namespace object. */ @@ -59,6 +75,13 @@ out_undo: list_for_each_entry_continue_reverse(ops, &pernet_list, list) { if (ops->exit) ops->exit(net); + if (&ops->list == first_device) { + LIST_HEAD(dev_kill_list); + rtnl_lock(); + unregister_netdevices(net, &dev_kill_list); + unregister_netdevice_many(&dev_kill_list); + rtnl_unlock(); + } } rcu_barrier(); @@ -147,18 +170,26 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) return net_create(); } +static DEFINE_SPINLOCK(cleanup_list_lock); +static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ + static void cleanup_net(struct work_struct *work) { struct pernet_operations *ops; - struct net *net; + struct net *net, *tmp; + LIST_HEAD(net_kill_list); - net = container_of(work, struct net, work); + /* Atomically snapshot the list of namespaces to cleanup */ + spin_lock_irq(&cleanup_list_lock); + list_replace_init(&cleanup_list, &net_kill_list); + spin_unlock_irq(&cleanup_list_lock); mutex_lock(&net_mutex); /* Don't let anyone else find us. */ rtnl_lock(); - list_del_rcu(&net->list); + list_for_each_entry(net, &net_kill_list, cleanup_list) + list_del_rcu(&net->list); rtnl_unlock(); /* @@ -170,8 +201,18 @@ static void cleanup_net(struct work_struct *work) /* Run all of the network namespace exit methods */ list_for_each_entry_reverse(ops, &pernet_list, list) { - if (ops->exit) - ops->exit(net); + if (ops->exit) { + list_for_each_entry(net, &net_kill_list, cleanup_list) + ops->exit(net); + } + if (&ops->list == first_device) { + LIST_HEAD(dev_kill_list); + rtnl_lock(); + list_for_each_entry(net, &net_kill_list, cleanup_list) + unregister_netdevices(net, &dev_kill_list); + unregister_netdevice_many(&dev_kill_list); + rtnl_unlock(); + } } mutex_unlock(&net_mutex); @@ -182,14 +223,23 @@ static void cleanup_net(struct work_struct *work) rcu_barrier(); /* Finally it is safe to free my network namespace structure */ - net_free(net); + list_for_each_entry_safe(net, tmp, &net_kill_list, cleanup_list) { + list_del_init(&net->cleanup_list); + net_free(net); + } } +static DECLARE_WORK(net_cleanup_work, cleanup_net); void __put_net(struct net *net) { /* Cleanup the network namespace in process context */ - INIT_WORK(&net->work, cleanup_net); - queue_work(netns_wq, &net->work); + unsigned long flags; + + spin_lock_irqsave(&cleanup_list_lock, flags); + list_add(&net->cleanup_list, &cleanup_list); + spin_unlock_irqrestore(&cleanup_list_lock, flags); + + queue_work(netns_wq, &net_cleanup_work); } EXPORT_SYMBOL_GPL(__put_net); -- cgit v1.2.3 From f875bae065334907796da12523f9df85c89f5712 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 22:25:28 +0000 Subject: net: Automatically allocate per namespace data. To get the full benefit of batched network namespace cleanup netowrk device deletion needs to be performed by the generic code. When using register_pernet_gen_device and freeing the data in exit_net it is impossible to delay allocation until after exit_net has called as the device uninit methods are no longer safe. To correct this, and to simplify working with per network namespace data I have moved allocation and deletion of per network namespace data into the network namespace core. The core now frees the data only after all of the network namespace exit routines have run. Now it is only required to set the new fields .id and .size in the pernet_operations structure if you want network namespace data to be managed for you automatically. This makes the current register_pernet_gen_device and register_pernet_gen_subsys routines unnecessary. For the moment I have left them as compatibility wrappers in net_namespace.h They will be removed once all of the users have been updated. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/net_namespace.h | 28 ++++++- net/core/net_namespace.c | 188 ++++++++++++++++++++++++-------------------- 2 files changed, 126 insertions(+), 90 deletions(-) (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index d69b4796030..080774b9dbf 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -236,6 +236,8 @@ struct pernet_operations { struct list_head list; int (*init)(struct net *net); void (*exit)(struct net *net); + int *id; + size_t size; }; /* @@ -259,12 +261,30 @@ struct pernet_operations { */ extern int register_pernet_subsys(struct pernet_operations *); extern void unregister_pernet_subsys(struct pernet_operations *); -extern int register_pernet_gen_subsys(int *id, struct pernet_operations *); -extern void unregister_pernet_gen_subsys(int id, struct pernet_operations *); extern int register_pernet_device(struct pernet_operations *); extern void unregister_pernet_device(struct pernet_operations *); -extern int register_pernet_gen_device(int *id, struct pernet_operations *); -extern void unregister_pernet_gen_device(int id, struct pernet_operations *); + +static inline int register_pernet_gen_subsys(int *id, struct pernet_operations *ops) +{ + ops->id = id; + return register_pernet_subsys(ops); +} + +static inline void unregister_pernet_gen_subsys(int id, struct pernet_operations *ops) +{ + return unregister_pernet_subsys(ops); +} + +static inline int register_pernet_gen_device(int *id, struct pernet_operations *ops) +{ + ops->id = id; + return register_pernet_device(ops); +} + +static inline void unregister_pernet_gen_device(int id, struct pernet_operations *ops) +{ + return unregister_pernet_device(ops); +} struct ctl_path; struct ctl_table; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index a42caa2b909..9679ad292da 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -43,13 +43,40 @@ static void unregister_netdevices(struct net *net, struct list_head *list) } } +static int ops_init(const struct pernet_operations *ops, struct net *net) +{ + int err; + if (ops->id && ops->size) { + void *data = kzalloc(ops->size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = net_assign_generic(net, *ops->id, data); + if (err) { + kfree(data); + return err; + } + } + if (ops->init) + return ops->init(net); + return 0; +} + +static void ops_free(const struct pernet_operations *ops, struct net *net) +{ + if (ops->id && ops->size) { + int id = *ops->id; + kfree(net_generic(net, id)); + } +} + /* * setup_net runs the initializers for the network namespace object. */ static __net_init int setup_net(struct net *net) { /* Must be called with net_mutex held */ - struct pernet_operations *ops; + const struct pernet_operations *ops, *saved_ops; int error = 0; atomic_set(&net->count, 1); @@ -59,11 +86,9 @@ static __net_init int setup_net(struct net *net) #endif list_for_each_entry(ops, &pernet_list, list) { - if (ops->init) { - error = ops->init(net); - if (error < 0) - goto out_undo; - } + error = ops_init(ops, net); + if (error < 0) + goto out_undo; } out: return error; @@ -72,6 +97,7 @@ out_undo: /* Walk through the list backwards calling the exit functions * for the pernet modules whose init functions did not fail. */ + saved_ops = ops; list_for_each_entry_continue_reverse(ops, &pernet_list, list) { if (ops->exit) ops->exit(net); @@ -83,6 +109,9 @@ out_undo: rtnl_unlock(); } } + ops = saved_ops; + list_for_each_entry_continue_reverse(ops, &pernet_list, list) + ops_free(ops, net); rcu_barrier(); goto out; @@ -175,7 +204,7 @@ static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ static void cleanup_net(struct work_struct *work) { - struct pernet_operations *ops; + const struct pernet_operations *ops; struct net *net, *tmp; LIST_HEAD(net_kill_list); @@ -214,6 +243,13 @@ static void cleanup_net(struct work_struct *work) rtnl_unlock(); } } + /* Free the net generic variables */ + list_for_each_entry_reverse(ops, &pernet_list, list) { + if (ops->size && ops->id) { + list_for_each_entry(net, &net_kill_list, cleanup_list) + ops_free(ops, net); + } + } mutex_unlock(&net_mutex); @@ -309,16 +345,16 @@ static int __init net_ns_init(void) pure_initcall(net_ns_init); #ifdef CONFIG_NET_NS -static int register_pernet_operations(struct list_head *list, - struct pernet_operations *ops) +static int __register_pernet_operations(struct list_head *list, + struct pernet_operations *ops) { struct net *net, *undo_net; int error; list_add_tail(&ops->list, list); - if (ops->init) { + if (ops->init || (ops->id && ops->size)) { for_each_net(net) { - error = ops->init(net); + error = ops_init(ops, net); if (error) goto out_undo; } @@ -336,10 +372,18 @@ out_undo: } } undone: + if (ops->size && ops->id) { + for_each_net(undo_net) { + if (net_eq(undo_net, net)) + goto freed; + ops_free(ops, undo_net); + } + } +freed: return error; } -static void unregister_pernet_operations(struct pernet_operations *ops) +static void __unregister_pernet_operations(struct pernet_operations *ops) { struct net *net; @@ -347,27 +391,66 @@ static void unregister_pernet_operations(struct pernet_operations *ops) if (ops->exit) for_each_net(net) ops->exit(net); + if (ops->id && ops->size) + for_each_net(net) + ops_free(ops, net); } #else -static int register_pernet_operations(struct list_head *list, - struct pernet_operations *ops) +static int __register_pernet_operations(struct list_head *list, + struct pernet_operations *ops) { - if (ops->init == NULL) - return 0; - return ops->init(&init_net); + int err = 0; + err = ops_init(ops, &init_net); + if (err) + ops_free(ops, &init_net); + return err; + } -static void unregister_pernet_operations(struct pernet_operations *ops) +static void __unregister_pernet_operations(struct pernet_operations *ops) { if (ops->exit) ops->exit(&init_net); + ops_free(ops, &init_net); } -#endif + +#endif /* CONFIG_NET_NS */ static DEFINE_IDA(net_generic_ids); +static int register_pernet_operations(struct list_head *list, + struct pernet_operations *ops) +{ + int error; + + if (ops->id) { +again: + error = ida_get_new_above(&net_generic_ids, 1, ops->id); + if (error < 0) { + if (error == -EAGAIN) { + ida_pre_get(&net_generic_ids, GFP_KERNEL); + goto again; + } + return error; + } + } + error = __register_pernet_operations(list, ops); + if (error && ops->id) + ida_remove(&net_generic_ids, *ops->id); + + return error; +} + +static void unregister_pernet_operations(struct pernet_operations *ops) +{ + + __unregister_pernet_operations(ops); + if (ops->id) + ida_remove(&net_generic_ids, *ops->id); +} + /** * register_pernet_subsys - register a network namespace subsystem * @ops: pernet operations structure for the subsystem @@ -414,38 +497,6 @@ void unregister_pernet_subsys(struct pernet_operations *module) } EXPORT_SYMBOL_GPL(unregister_pernet_subsys); -int register_pernet_gen_subsys(int *id, struct pernet_operations *ops) -{ - int rv; - - mutex_lock(&net_mutex); -again: - rv = ida_get_new_above(&net_generic_ids, 1, id); - if (rv < 0) { - if (rv == -EAGAIN) { - ida_pre_get(&net_generic_ids, GFP_KERNEL); - goto again; - } - goto out; - } - rv = register_pernet_operations(first_device, ops); - if (rv < 0) - ida_remove(&net_generic_ids, *id); -out: - mutex_unlock(&net_mutex); - return rv; -} -EXPORT_SYMBOL_GPL(register_pernet_gen_subsys); - -void unregister_pernet_gen_subsys(int id, struct pernet_operations *ops) -{ - mutex_lock(&net_mutex); - unregister_pernet_operations(ops); - ida_remove(&net_generic_ids, id); - mutex_unlock(&net_mutex); -} -EXPORT_SYMBOL_GPL(unregister_pernet_gen_subsys); - /** * register_pernet_device - register a network namespace device * @ops: pernet operations structure for the subsystem @@ -477,30 +528,6 @@ int register_pernet_device(struct pernet_operations *ops) } EXPORT_SYMBOL_GPL(register_pernet_device); -int register_pernet_gen_device(int *id, struct pernet_operations *ops) -{ - int error; - mutex_lock(&net_mutex); -again: - error = ida_get_new_above(&net_generic_ids, 1, id); - if (error) { - if (error == -EAGAIN) { - ida_pre_get(&net_generic_ids, GFP_KERNEL); - goto again; - } - goto out; - } - error = register_pernet_operations(&pernet_list, ops); - if (error) - ida_remove(&net_generic_ids, *id); - else if (first_device == &pernet_list) - first_device = &ops->list; -out: - mutex_unlock(&net_mutex); - return error; -} -EXPORT_SYMBOL_GPL(register_pernet_gen_device); - /** * unregister_pernet_device - unregister a network namespace netdevice * @ops: pernet operations structure to manipulate @@ -520,17 +547,6 @@ void unregister_pernet_device(struct pernet_operations *ops) } EXPORT_SYMBOL_GPL(unregister_pernet_device); -void unregister_pernet_gen_device(int id, struct pernet_operations *ops) -{ - mutex_lock(&net_mutex); - if (&ops->list == first_device) - first_device = first_device->next; - unregister_pernet_operations(ops); - ida_remove(&net_generic_ids, id); - mutex_unlock(&net_mutex); -} -EXPORT_SYMBOL_GPL(unregister_pernet_gen_device); - static void net_generic_release(struct rcu_head *rcu) { struct net_generic *ng; -- cgit v1.2.3 From e008b5fc8dc7f46d9904001c7a2155eb1e7d35ab Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 22:25:30 +0000 Subject: net: Simplfy default_device_exit and improve batching. - Defer dellink to net_cleanup() allowing for batching. - Fix comment. - Use for_each_netdev_safe again as dev_change_net_namespace touches at most one network device (unlike veth dellink). Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/core/dev.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index bb37ee1e090..e3e18dee0bd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5736,14 +5736,13 @@ static struct pernet_operations __net_initdata netdev_net_ops = { static void __net_exit default_device_exit(struct net *net) { - struct net_device *dev; + struct net_device *dev, *aux; /* - * Push all migratable of the network devices back to the + * Push all migratable network devices back to the * initial network namespace */ rtnl_lock(); -restart: - for_each_netdev(net, dev) { + for_each_netdev_safe(net, dev, aux) { int err; char fb_name[IFNAMSIZ]; @@ -5751,11 +5750,9 @@ restart: if (dev->features & NETIF_F_NETNS_LOCAL) continue; - /* Delete virtual devices */ - if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) { - dev->rtnl_link_ops->dellink(dev, NULL); - goto restart; - } + /* Leave virtual devices for the generic cleanup */ + if (dev->rtnl_link_ops) + continue; /* Push remaing network devices to init_net */ snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex); @@ -5765,7 +5762,6 @@ restart: __func__, dev->name, err); BUG(); } - goto restart; } rtnl_unlock(); } -- cgit v1.2.3 From 946d1a9298c9e592b189a168326603c92d782b5f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:05 +0000 Subject: net: Simplify vlan pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/8021q/vlan.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 225aa2fac0e..91e9073e199 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -686,47 +686,28 @@ out: static int vlan_init_net(struct net *net) { + struct vlan_net *vn = net_generic(net, vlan_net_id); int err; - struct vlan_net *vn; - - err = -ENOMEM; - vn = kzalloc(sizeof(struct vlan_net), GFP_KERNEL); - if (vn == NULL) - goto err_alloc; - - err = net_assign_generic(net, vlan_net_id, vn); - if (err < 0) - goto err_assign; vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; err = vlan_proc_init(net); - if (err < 0) - goto err_proc; - return 0; - -err_proc: - /* nothing */ -err_assign: - kfree(vn); -err_alloc: return err; } static void vlan_exit_net(struct net *net) { - struct vlan_net *vn; - - vn = net_generic(net, vlan_net_id); rtnl_kill_links(net, &vlan_link_ops); + vlan_proc_cleanup(net); - kfree(vn); } static struct pernet_operations vlan_net_ops = { .init = vlan_init_net, .exit = vlan_exit_net, + .id = &vlan_net_id, + .size = sizeof(struct vlan_net), }; static int __init vlan_proto_init(void) @@ -736,7 +717,7 @@ static int __init vlan_proto_init(void) pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); pr_info("All bugs added by %s\n", vlan_buggyright); - err = register_pernet_gen_device(&vlan_net_id, &vlan_net_ops); + err = register_pernet_device(&vlan_net_ops); if (err < 0) goto err0; @@ -761,7 +742,7 @@ err4: err3: unregister_netdevice_notifier(&vlan_notifier_block); err2: - unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); + unregister_pernet_device(&vlan_net_ops); err0: return err; } @@ -781,7 +762,7 @@ static void __exit vlan_cleanup_module(void) for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) BUG_ON(!hlist_empty(&vlan_group_hash[i])); - unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); + unregister_pernet_device(&vlan_net_ops); rcu_barrier(); /* Wait for completion of call_rcu()'s */ vlan_gvrp_uninit(); -- cgit v1.2.3 From 23c049ca92548483d5e12c94cc983afb3040f626 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:06 +0000 Subject: net: Simplify af_key pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/key/af_key.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/key/af_key.c b/net/key/af_key.c index 478c8b32a5f..84209fbbeb1 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3765,28 +3765,14 @@ static struct xfrm_mgr pfkeyv2_mgr = static int __net_init pfkey_net_init(struct net *net) { - struct netns_pfkey *net_pfkey; + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); int rv; - net_pfkey = kmalloc(sizeof(struct netns_pfkey), GFP_KERNEL); - if (!net_pfkey) { - rv = -ENOMEM; - goto out_kmalloc; - } INIT_HLIST_HEAD(&net_pfkey->table); atomic_set(&net_pfkey->socks_nr, 0); - rv = net_assign_generic(net, pfkey_net_id, net_pfkey); - if (rv < 0) - goto out_assign; + rv = pfkey_init_proc(net); - if (rv < 0) - goto out_proc; - return 0; -out_proc: -out_assign: - kfree(net_pfkey); -out_kmalloc: return rv; } @@ -3796,17 +3782,18 @@ static void __net_exit pfkey_net_exit(struct net *net) pfkey_exit_proc(net); BUG_ON(!hlist_empty(&net_pfkey->table)); - kfree(net_pfkey); } static struct pernet_operations pfkey_net_ops = { .init = pfkey_net_init, .exit = pfkey_net_exit, + .id = &pfkey_net_id, + .size = sizeof(struct netns_pfkey), }; static void __exit ipsec_pfkey_exit(void) { - unregister_pernet_gen_subsys(pfkey_net_id, &pfkey_net_ops); + unregister_pernet_subsys(&pfkey_net_ops); xfrm_unregister_km(&pfkeyv2_mgr); sock_unregister(PF_KEY); proto_unregister(&key_proto); @@ -3825,7 +3812,7 @@ static int __init ipsec_pfkey_init(void) err = xfrm_register_km(&pfkeyv2_mgr); if (err != 0) goto out_sock_unregister; - err = register_pernet_gen_subsys(&pfkey_net_id, &pfkey_net_ops); + err = register_pernet_subsys(&pfkey_net_ops); if (err != 0) goto out_xfrm_unregister_km; out: -- cgit v1.2.3 From 32b51f92d858dd3002ec2240960b772518a6803b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:07 +0000 Subject: net: Simplify conntrack_proto_dccp pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_proto_dccp.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 80abdf297b3..98916ef26f5 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -810,12 +810,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { static __net_init int dccp_net_init(struct net *net) { - struct dccp_net *dn; - int err; - - dn = kmalloc(sizeof(*dn), GFP_KERNEL); - if (!dn) - return -ENOMEM; + struct dccp_net *dn = dccp_pernet(net); /* default values */ dn->dccp_loose = 1; @@ -827,16 +822,11 @@ static __net_init int dccp_net_init(struct net *net) dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; - err = net_assign_generic(net, dccp_net_id, dn); - if (err) - goto out; - #ifdef CONFIG_SYSCTL - err = -ENOMEM; dn->sysctl_table = kmemdup(dccp_sysctl_table, sizeof(dccp_sysctl_table), GFP_KERNEL); if (!dn->sysctl_table) - goto out; + return -ENOMEM; dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST]; dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND]; @@ -851,15 +841,11 @@ static __net_init int dccp_net_init(struct net *net) nf_net_netfilter_sysctl_path, dn->sysctl_table); if (!dn->sysctl_header) { kfree(dn->sysctl_table); - goto out; + return -ENOMEM; } #endif return 0; - -out: - kfree(dn); - return err; } static __net_exit void dccp_net_exit(struct net *net) @@ -869,21 +855,20 @@ static __net_exit void dccp_net_exit(struct net *net) unregister_net_sysctl_table(dn->sysctl_header); kfree(dn->sysctl_table); #endif - kfree(dn); - - net_assign_generic(net, dccp_net_id, NULL); } static struct pernet_operations dccp_net_ops = { .init = dccp_net_init, .exit = dccp_net_exit, + .id = &dccp_net_id, + .size = sizeof(struct dccp_net), }; static int __init nf_conntrack_proto_dccp_init(void) { int err; - err = register_pernet_gen_subsys(&dccp_net_id, &dccp_net_ops); + err = register_pernet_subsys(&dccp_net_ops); if (err < 0) goto err1; @@ -899,14 +884,14 @@ static int __init nf_conntrack_proto_dccp_init(void) err3: nf_conntrack_l4proto_unregister(&dccp_proto4); err2: - unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops); + unregister_pernet_subsys(&dccp_net_ops); err1: return err; } static void __exit nf_conntrack_proto_dccp_fini(void) { - unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops); + unregister_pernet_subsys(&dccp_net_ops); nf_conntrack_l4proto_unregister(&dccp_proto6); nf_conntrack_l4proto_unregister(&dccp_proto4); } -- cgit v1.2.3 From e8d02885997081f09272af6b9a27061a142da4c5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:08 +0000 Subject: net: Simplify conntrack_proto_gre pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_proto_gre.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 91d0e719d67..c99cfba64dd 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -300,32 +300,24 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { static int proto_gre_net_init(struct net *net) { - struct netns_proto_gre *net_gre; - int rv; + struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); - net_gre = kmalloc(sizeof(struct netns_proto_gre), GFP_KERNEL); - if (!net_gre) - return -ENOMEM; rwlock_init(&net_gre->keymap_lock); INIT_LIST_HEAD(&net_gre->keymap_list); - rv = net_assign_generic(net, proto_gre_net_id, net_gre); - if (rv < 0) - kfree(net_gre); - return rv; + return 0; } static void proto_gre_net_exit(struct net *net) { - struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id); - nf_ct_gre_keymap_flush(net); - kfree(net_gre); } static struct pernet_operations proto_gre_net_ops = { .init = proto_gre_net_init, .exit = proto_gre_net_exit, + .id = &proto_gre_net_id, + .size = sizeof(struct netns_proto_gre), }; static int __init nf_ct_proto_gre_init(void) @@ -335,7 +327,7 @@ static int __init nf_ct_proto_gre_init(void) rv = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4); if (rv < 0) return rv; - rv = register_pernet_gen_subsys(&proto_gre_net_id, &proto_gre_net_ops); + rv = register_pernet_subsys(&proto_gre_net_ops); if (rv < 0) nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); return rv; @@ -344,7 +336,7 @@ static int __init nf_ct_proto_gre_init(void) static void __exit nf_ct_proto_gre_fini(void) { nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); - unregister_pernet_gen_subsys(proto_gre_net_id, &proto_gre_net_ops); + unregister_pernet_subsys(&proto_gre_net_ops); } module_init(nf_ct_proto_gre_init); -- cgit v1.2.3 From d2b3eb630767f0b0ae21566b1b88cb512f40c647 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:12 +0000 Subject: net: Simplify phonet pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/phonet/pn_dev.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index d87388c94b0..bc4a33bf2d3 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -313,19 +313,14 @@ static struct notifier_block phonet_device_notifier = { /* Per-namespace Phonet devices handling */ static int phonet_init_net(struct net *net) { - struct phonet_net *pnn = kzalloc(sizeof(*pnn), GFP_KERNEL); - if (!pnn) - return -ENOMEM; + struct phonet_net *pnn = net_generic(net, phonet_net_id); - if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) { - kfree(pnn); + if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) return -ENOMEM; - } INIT_LIST_HEAD(&pnn->pndevs.list); mutex_init(&pnn->pndevs.lock); mutex_init(&pnn->routes.lock); - net_assign_generic(net, phonet_net_id, pnn); return 0; } @@ -349,18 +344,19 @@ static void phonet_exit_net(struct net *net) rtnl_unlock(); proc_net_remove(net, "phonet"); - kfree(pnn); } static struct pernet_operations phonet_net_ops = { .init = phonet_init_net, .exit = phonet_exit_net, + .id = &phonet_net_id, + .size = sizeof(struct phonet_net), }; /* Initialize Phonet devices list */ int __init phonet_device_init(void) { - int err = register_pernet_gen_device(&phonet_net_id, &phonet_net_ops); + int err = register_pernet_device(&phonet_net_ops); if (err) return err; @@ -375,7 +371,7 @@ void phonet_device_exit(void) { rtnl_unregister_all(PF_PHONET); unregister_netdevice_notifier(&phonet_device_notifier); - unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops); + unregister_pernet_device(&phonet_net_ops); } int phonet_route_add(struct net_device *dev, u8 daddr) -- cgit v1.2.3 From cfb8fbf2299d0e028ac59afd5b8c94ebe53d0859 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:13 +0000 Subject: net: Simplify ip_gre pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index c5f6af5d0f3..f36ce156cac 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1309,17 +1309,8 @@ static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head) static int ipgre_init_net(struct net *net) { + struct ipgre_net *ign = net_generic(net, ipgre_net_id); int err; - struct ipgre_net *ign; - - err = -ENOMEM; - ign = kzalloc(sizeof(struct ipgre_net), GFP_KERNEL); - if (ign == NULL) - goto err_alloc; - - err = net_assign_generic(net, ipgre_net_id, ign); - if (err < 0) - goto err_assign; ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0", ipgre_tunnel_setup); @@ -1340,10 +1331,6 @@ static int ipgre_init_net(struct net *net) err_reg_dev: free_netdev(ign->fb_tunnel_dev); err_alloc_dev: - /* nothing */ -err_assign: - kfree(ign); -err_alloc: return err; } @@ -1357,12 +1344,13 @@ static void ipgre_exit_net(struct net *net) ipgre_destroy_tunnels(ign, &list); unregister_netdevice_many(&list); rtnl_unlock(); - kfree(ign); } static struct pernet_operations ipgre_net_ops = { .init = ipgre_init_net, .exit = ipgre_exit_net, + .id = &ipgre_net_id, + .size = sizeof(struct ipgre_net), }; static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -1682,7 +1670,7 @@ static int __init ipgre_init(void) return -EAGAIN; } - err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops); + err = register_pernet_device(&ipgre_net_ops); if (err < 0) goto gen_device_failed; @@ -1700,7 +1688,7 @@ out: tap_ops_failed: rtnl_link_unregister(&ipgre_link_ops); rtnl_link_failed: - unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); + unregister_pernet_device(&ipgre_net_ops); gen_device_failed: inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); goto out; @@ -1710,7 +1698,7 @@ static void __exit ipgre_fini(void) { rtnl_link_unregister(&ipgre_tap_ops); rtnl_link_unregister(&ipgre_link_ops); - unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); + unregister_pernet_device(&ipgre_net_ops); if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) printk(KERN_INFO "ipgre close: can't remove protocol\n"); } -- cgit v1.2.3 From 86de8a631e90a96d136ffd877719471a0b8d8b6d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:14 +0000 Subject: net: Simplify ipip pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 7242ffcc44e..eda04fed337 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -775,17 +775,8 @@ static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head) static int ipip_init_net(struct net *net) { + struct ipip_net *ipn = net_generic(net, ipip_net_id); int err; - struct ipip_net *ipn; - - err = -ENOMEM; - ipn = kzalloc(sizeof(struct ipip_net), GFP_KERNEL); - if (ipn == NULL) - goto err_alloc; - - err = net_assign_generic(net, ipip_net_id, ipn); - if (err < 0) - goto err_assign; ipn->tunnels[0] = ipn->tunnels_wc; ipn->tunnels[1] = ipn->tunnels_l; @@ -812,29 +803,26 @@ err_reg_dev: free_netdev(ipn->fb_tunnel_dev); err_alloc_dev: /* nothing */ -err_assign: - kfree(ipn); -err_alloc: return err; } static void ipip_exit_net(struct net *net) { - struct ipip_net *ipn; + struct ipip_net *ipn = net_generic(net, ipip_net_id); LIST_HEAD(list); - ipn = net_generic(net, ipip_net_id); rtnl_lock(); ipip_destroy_tunnels(ipn, &list); unregister_netdevice_queue(ipn->fb_tunnel_dev, &list); unregister_netdevice_many(&list); rtnl_unlock(); - kfree(ipn); } static struct pernet_operations ipip_net_ops = { .init = ipip_init_net, .exit = ipip_exit_net, + .id = &ipip_net_id, + .size = sizeof(struct ipip_net), }; static int __init ipip_init(void) @@ -848,7 +836,7 @@ static int __init ipip_init(void) return -EAGAIN; } - err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops); + err = register_pernet_device(&ipip_net_ops); if (err) xfrm4_tunnel_deregister(&ipip_handler, AF_INET); @@ -860,7 +848,7 @@ static void __exit ipip_fini(void) if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) printk(KERN_INFO "ipip close: can't deregister tunnel\n"); - unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops); + unregister_pernet_device(&ipip_net_ops); } module_init(ipip_init); -- cgit v1.2.3 From ac31cd3cbadc45d6ed2a0ae5d116918b15bb6c22 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:15 +0000 Subject: net: Simplify ip6_tunnel pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index e5c0f6bb831..d453d07b0df 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1409,17 +1409,8 @@ static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) static int ip6_tnl_init_net(struct net *net) { + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); int err; - struct ip6_tnl_net *ip6n; - - err = -ENOMEM; - ip6n = kzalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); - if (ip6n == NULL) - goto err_alloc; - - err = net_assign_generic(net, ip6_tnl_net_id, ip6n); - if (err < 0) - goto err_assign; ip6n->tnls[0] = ip6n->tnls_wc; ip6n->tnls[1] = ip6n->tnls_r_l; @@ -1442,27 +1433,23 @@ static int ip6_tnl_init_net(struct net *net) err_register: free_netdev(ip6n->fb_tnl_dev); err_alloc_dev: - /* nothing */ -err_assign: - kfree(ip6n); -err_alloc: return err; } static void ip6_tnl_exit_net(struct net *net) { - struct ip6_tnl_net *ip6n; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - ip6n = net_generic(net, ip6_tnl_net_id); rtnl_lock(); ip6_tnl_destroy_tunnels(ip6n); rtnl_unlock(); - kfree(ip6n); } static struct pernet_operations ip6_tnl_net_ops = { .init = ip6_tnl_init_net, .exit = ip6_tnl_exit_net, + .id = &ip6_tnl_net_id, + .size = sizeof(struct ip6_tnl_net), }; /** @@ -1487,7 +1474,7 @@ static int __init ip6_tunnel_init(void) goto unreg_ip4ip6; } - err = register_pernet_gen_device(&ip6_tnl_net_id, &ip6_tnl_net_ops); + err = register_pernet_device(&ip6_tnl_net_ops); if (err < 0) goto err_pernet; return 0; @@ -1511,7 +1498,7 @@ static void __exit ip6_tunnel_cleanup(void) if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); - unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); + unregister_pernet_device(&ip6_tnl_net_ops); } module_init(ip6_tunnel_init); -- cgit v1.2.3 From 671011720baa222b6de667cd688aed4dc8908924 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 29 Nov 2009 15:46:16 +0000 Subject: net: Simplify ipip6 aka sit pernet operations. Take advantage of the new pernet automatic storage management, and stop using compatibility network namespace functions. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/ipv6/sit.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d9deaa7753e..976e68244b9 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1164,17 +1164,8 @@ static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) static int sit_init_net(struct net *net) { + struct sit_net *sitn = net_generic(net, sit_net_id); int err; - struct sit_net *sitn; - - err = -ENOMEM; - sitn = kzalloc(sizeof(struct sit_net), GFP_KERNEL); - if (sitn == NULL) - goto err_alloc; - - err = net_assign_generic(net, sit_net_id, sitn); - if (err < 0) - goto err_assign; sitn->tunnels[0] = sitn->tunnels_wc; sitn->tunnels[1] = sitn->tunnels_l; @@ -1201,37 +1192,33 @@ err_reg_dev: dev_put(sitn->fb_tunnel_dev); free_netdev(sitn->fb_tunnel_dev); err_alloc_dev: - /* nothing */ -err_assign: - kfree(sitn); -err_alloc: return err; } static void sit_exit_net(struct net *net) { - struct sit_net *sitn; + struct sit_net *sitn = net_generic(net, sit_net_id); LIST_HEAD(list); - sitn = net_generic(net, sit_net_id); rtnl_lock(); sit_destroy_tunnels(sitn, &list); unregister_netdevice_queue(sitn->fb_tunnel_dev, &list); unregister_netdevice_many(&list); rtnl_unlock(); - kfree(sitn); } static struct pernet_operations sit_net_ops = { .init = sit_init_net, .exit = sit_exit_net, + .id = &sit_net_id, + .size = sizeof(struct sit_net), }; static void __exit sit_cleanup(void) { xfrm4_tunnel_deregister(&sit_handler, AF_INET6); - unregister_pernet_gen_device(sit_net_id, &sit_net_ops); + unregister_pernet_device(&sit_net_ops); rcu_barrier(); /* Wait for completion of call_rcu()'s */ } @@ -1246,7 +1233,7 @@ static int __init sit_init(void) return -EAGAIN; } - err = register_pernet_gen_device(&sit_net_id, &sit_net_ops); + err = register_pernet_device(&sit_net_ops); if (err < 0) xfrm4_tunnel_deregister(&sit_handler, AF_INET6); -- cgit v1.2.3 From 810c07194f6ef541625e65b53392e9f605611a1a Mon Sep 17 00:00:00 2001 From: Andrei Pelinescu-Onciul Date: Wed, 2 Dec 2009 01:16:49 -0800 Subject: sctp: fix sctp_setsockopt_autoclose compile warning Fix the following warning, when building on 64 bits: net/sctp/socket.c:2091: warning: large integer implicitly truncated to unsigned type Signed-off-by: Andrei Pelinescu-Onciul Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5fa9ac52e13..89ab66e5474 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2088,7 +2088,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, return -EFAULT; /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */ if (sp->autoclose > (MAX_SCHEDULE_TIMEOUT / HZ) ) - sp->autoclose = MAX_SCHEDULE_TIMEOUT / HZ ; + sp->autoclose = (__u32)(MAX_SCHEDULE_TIMEOUT / HZ) ; return 0; } -- cgit v1.2.3 From d7256d0eb4c82b789125f610fea11c6e82b1bcff Mon Sep 17 00:00:00 2001 From: Jean-Mickael Guerin Date: Tue, 1 Dec 2009 08:47:26 +0000 Subject: net: compat_mmsghdr must be used in sys_recvmmsg Both to traverse the entries and to set the msg_len field. Commiter note: folded two patches and avoided one branch repeating the compat test. Signed-off-by: Jean-Mickael Guerin Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/socket.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index 402abb39cbf..b94c3dd7101 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2144,6 +2144,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, int fput_needed, err, datagrams; struct socket *sock; struct mmsghdr __user *entry; + struct compat_mmsghdr __user *compat_entry; struct msghdr msg_sys; struct timespec end_time; @@ -2163,19 +2164,30 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, goto out_put; entry = mmsg; + compat_entry = (struct compat_mmsghdr __user *)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 (MSG_CMSG_COMPAT & flags) { + err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry, + &msg_sys, flags, datagrams); + if (err < 0) + break; + err = __put_user(err, &compat_entry->msg_len); + ++compat_entry; + } else { + err = __sys_recvmsg(sock, (struct msghdr __user *)entry, + &msg_sys, flags, datagrams); + if (err < 0) + break; + err = put_user(err, &entry->msg_len); + ++entry; + } + if (err) break; - ++entry; ++datagrams; if (timeout) { -- cgit v1.2.3 From 5b23136bcf766a58160a319677b366c90f0cd223 Mon Sep 17 00:00:00 2001 From: Jean-Mickael Guerin Date: Tue, 1 Dec 2009 07:52:16 +0000 Subject: net: compat_sys_recvmmsg user timespec arg can be NULL We must test if user timespec is non-NULL before copying from userpace, same as sys_recvmmsg(). Commiter note: changed it so that we have just one branch. Signed-off-by: Jean-Mickael Guerin Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/compat.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/compat.c b/net/compat.c index 6a2f75fb3f4..e1a56ade803 100644 --- a/net/compat.c +++ b/net/compat.c @@ -758,9 +758,13 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, { int datagrams; struct timespec ktspec; - struct compat_timespec __user *utspec = - (struct compat_timespec __user *)timeout; + struct compat_timespec __user *utspec; + if (timeout == NULL) + return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, + flags | MSG_CMSG_COMPAT, NULL); + + 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; -- cgit v1.2.3 From c81c2d95449cd218c2022ce6014c52fef1eb1f66 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 2 Dec 2009 16:49:02 +0000 Subject: skbuff: remove skb_dma_map/unmap The two functions skb_dma_map/unmap are unsafe to use as they cause problems when packets are cloned and sent to multiple devices while a HW IOMMU is enabled. Due to this it is best to remove the code so it is not used by any other network driver maintainters. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/linux/skbuff.h | 8 ------- net/core/Makefile | 1 - net/core/skb_dma_map.c | 65 -------------------------------------------------- 3 files changed, 74 deletions(-) delete mode 100644 net/core/skb_dma_map.c (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 89eed8cdd31..ae836fded53 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -416,14 +416,6 @@ struct sk_buff { #include -#ifdef CONFIG_HAS_DMA -#include -extern int skb_dma_map(struct device *dev, struct sk_buff *skb, - enum dma_data_direction dir); -extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb, - enum dma_data_direction dir); -#endif - static inline struct dst_entry *skb_dst(const struct sk_buff *skb) { return (struct dst_entry *)skb->_skb_dst; diff --git a/net/core/Makefile b/net/core/Makefile index 796f46eece5..08791ac3e05 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -6,7 +6,6 @@ obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ gen_stats.o gen_estimator.o net_namespace.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o -obj-$(CONFIG_HAS_DMA) += skb_dma_map.o obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c deleted file mode 100644 index 79687dfd695..00000000000 --- a/net/core/skb_dma_map.c +++ /dev/null @@ -1,65 +0,0 @@ -/* skb_dma_map.c: DMA mapping helpers for socket buffers. - * - * Copyright (C) David S. Miller - */ - -#include -#include -#include -#include - -int skb_dma_map(struct device *dev, struct sk_buff *skb, - enum dma_data_direction dir) -{ - struct skb_shared_info *sp = skb_shinfo(skb); - dma_addr_t map; - int i; - - map = dma_map_single(dev, skb->data, - skb_headlen(skb), dir); - if (dma_mapping_error(dev, map)) - goto out_err; - - sp->dma_head = map; - for (i = 0; i < sp->nr_frags; i++) { - skb_frag_t *fp = &sp->frags[i]; - - map = dma_map_page(dev, fp->page, fp->page_offset, - fp->size, dir); - if (dma_mapping_error(dev, map)) - goto unwind; - sp->dma_maps[i] = map; - } - - return 0; - -unwind: - while (--i >= 0) { - skb_frag_t *fp = &sp->frags[i]; - - dma_unmap_page(dev, sp->dma_maps[i], - fp->size, dir); - } - dma_unmap_single(dev, sp->dma_head, - skb_headlen(skb), dir); -out_err: - return -ENOMEM; -} -EXPORT_SYMBOL(skb_dma_map); - -void skb_dma_unmap(struct device *dev, struct sk_buff *skb, - enum dma_data_direction dir) -{ - struct skb_shared_info *sp = skb_shinfo(skb); - int i; - - dma_unmap_single(dev, sp->dma_head, - skb_headlen(skb), dir); - for (i = 0; i < sp->nr_frags; i++) { - skb_frag_t *fp = &sp->frags[i]; - - dma_unmap_page(dev, sp->dma_maps[i], - fp->size, dir); - } -} -EXPORT_SYMBOL(skb_dma_unmap); -- cgit v1.2.3 From e6b4d11367519bc71729c09d05a126b133c755be Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Wed, 2 Dec 2009 18:07:39 +0000 Subject: TCPCT part 1a: add request_values parameter for sending SYNACK Add optional function parameters associated with sending SYNACK. These parameters are not needed after sending SYNACK, and are not used for retransmission. Avoids extending struct tcp_request_sock, and avoids allocating kernel memory. Also affects DCCP as it uses common struct request_sock_ops, but this parameter is currently reserved for future use. Signed-off-by: William.Allen.Simpson@gmail.com Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/request_sock.h | 8 +++++++- include/net/tcp.h | 3 ++- net/dccp/ipv4.c | 5 +++-- net/dccp/ipv6.c | 5 +++-- net/dccp/minisocks.c | 2 +- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/tcp_ipv4.c | 18 ++++++++++-------- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 3 ++- net/ipv6/tcp_ipv6.c | 27 ++++++++++++--------------- 10 files changed, 42 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/include/net/request_sock.h b/include/net/request_sock.h index c7190846e12..c9b50ebd9ce 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -27,13 +27,19 @@ struct sk_buff; struct dst_entry; struct proto; +/* empty to "strongly type" an otherwise void parameter. + */ +struct request_values { +}; + struct request_sock_ops { int family; int obj_size; struct kmem_cache *slab; char *slab_name; int (*rtx_syn_ack)(struct sock *sk, - struct request_sock *req); + struct request_sock *req, + struct request_values *rvp); void (*send_ack)(struct sock *sk, struct sk_buff *skb, struct request_sock *req); void (*send_reset)(struct sock *sk, diff --git a/include/net/tcp.h b/include/net/tcp.h index 325bfcf5c93..ec183fda05d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -440,7 +440,8 @@ extern int tcp_connect(struct sock *sk); extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, - struct request_sock *req); + struct request_sock *req, + struct request_values *rvp); extern int tcp_disconnect(struct sock *sk, int flags); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2423a086673..efbcfdc1279 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -477,7 +477,8 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, return &rt->u.dst; } -static int dccp_v4_send_response(struct sock *sk, struct request_sock *req) +static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, + struct request_values *rv_unused) { int err = -1; struct sk_buff *skb; @@ -626,7 +627,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) dreq->dreq_iss = dccp_v4_init_sequence(skb); dreq->dreq_service = service; - if (dccp_v4_send_response(sk, req)) + if (dccp_v4_send_response(sk, req, NULL)) goto drop_and_free; inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 50ea91a7770..6574215a1f5 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -241,7 +241,8 @@ out: } -static int dccp_v6_send_response(struct sock *sk, struct request_sock *req) +static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, + struct request_values *rv_unused) { struct inet6_request_sock *ireq6 = inet6_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); @@ -468,7 +469,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) dreq->dreq_iss = dccp_v6_init_sequence(skb); dreq->dreq_service = service; - if (dccp_v6_send_response(sk, req)) + if (dccp_v6_send_response(sk, req, NULL)) goto drop_and_free; inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 5ca49cec95f..af226a06314 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -184,7 +184,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, * counter (backoff, monitored by dccp_response_timer). */ req->retrans++; - req->rsk_ops->rtx_syn_ack(sk, req); + req->rsk_ops->rtx_syn_ack(sk, req, NULL); } /* Network Duplicate, discard packet */ return NULL; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 9b35c56d102..ee16475f8fc 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -531,7 +531,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, &expire, &resend); if (!expire && (!resend || - !req->rsk_ops->rtx_syn_ack(parent, req) || + !req->rsk_ops->rtx_syn_ack(parent, req, NULL) || inet_rsk(req)->acked)) { unsigned long timeo; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index df18ce04f41..649a36d99c7 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -742,8 +742,9 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, * This still operates on a request_sock only, not on a big * socket. */ -static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req, - struct dst_entry *dst) +static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, + struct request_sock *req, + struct request_values *rvp) { const struct inet_request_sock *ireq = inet_rsk(req); int err = -1; @@ -753,7 +754,7 @@ static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req, if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL) return -1; - skb = tcp_make_synack(sk, dst, req); + skb = tcp_make_synack(sk, dst, req, rvp); if (skb) { struct tcphdr *th = tcp_hdr(skb); @@ -774,9 +775,10 @@ static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req, return err; } -static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req) +static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, + struct request_values *rvp) { - return __tcp_v4_send_synack(sk, req, NULL); + return __tcp_v4_send_synack(sk, NULL, req, rvp); } /* @@ -1211,13 +1213,13 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = { int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) { - struct inet_request_sock *ireq; struct tcp_options_received tmp_opt; struct request_sock *req; + struct inet_request_sock *ireq; + struct dst_entry *dst = NULL; __be32 saddr = ip_hdr(skb)->saddr; __be32 daddr = ip_hdr(skb)->daddr; __u32 isn = TCP_SKB_CB(skb)->when; - struct dst_entry *dst = NULL; #ifdef CONFIG_SYN_COOKIES int want_cookie = 0; #else @@ -1337,7 +1339,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) } tcp_rsk(req)->snt_isn = isn; - if (__tcp_v4_send_synack(sk, req, dst) || want_cookie) + if (__tcp_v4_send_synack(sk, dst, req, NULL) || want_cookie) goto drop_and_free; inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index ab32c181f74..d3f6bbfc76f 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -531,7 +531,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * Enforce "SYN-ACK" according to figure 8, figure 6 * of RFC793, fixed by RFC1122. */ - req->rsk_ops->rtx_syn_ack(sk, req); + req->rsk_ops->rtx_syn_ack(sk, req, NULL); return NULL; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 875bc6dcd92..b8b25049f25 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2224,7 +2224,8 @@ int tcp_send_synack(struct sock *sk) /* Prepare a SYN-ACK. */ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, - struct request_sock *req) + struct request_sock *req, + struct request_values *rvp) { struct inet_request_sock *ireq = inet_rsk(req); struct tcp_sock *tp = tcp_sk(sk); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index de709091b26..da6e24416d7 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -461,7 +461,8 @@ out: } -static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) +static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, + struct request_values *rvp) { struct inet6_request_sock *treq = inet6_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); @@ -499,7 +500,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) goto done; - skb = tcp_make_synack(sk, dst, req); + skb = tcp_make_synack(sk, dst, req, rvp); if (skb) { struct tcphdr *th = tcp_hdr(skb); @@ -1161,13 +1162,13 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) */ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) { + struct tcp_options_received tmp_opt; + struct request_sock *req; struct inet6_request_sock *treq; struct ipv6_pinfo *np = inet6_sk(sk); - struct tcp_options_received tmp_opt; struct tcp_sock *tp = tcp_sk(sk); - struct request_sock *req = NULL; - __u32 isn = TCP_SKB_CB(skb)->when; struct dst_entry *dst = __sk_dst_get(sk); + __u32 isn = TCP_SKB_CB(skb)->when; #ifdef CONFIG_SYN_COOKIES int want_cookie = 0; #else @@ -1239,23 +1240,19 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) isn = tcp_v6_init_sequence(skb); } - tcp_rsk(req)->snt_isn = isn; security_inet_conn_request(sk, skb, req); - if (tcp_v6_send_synack(sk, req)) - goto drop; + if (tcp_v6_send_synack(sk, req, NULL) || want_cookie) + goto drop_and_free; - if (!want_cookie) { - inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); - return 0; - } + inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); + return 0; +drop_and_free: + reqsk_free(req); drop: - if (req) - reqsk_free(req); - return 0; /* don't send reset */ } -- cgit v1.2.3 From da5c78c82629a167794436e4306b4cf1faddea90 Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Wed, 2 Dec 2009 18:12:09 +0000 Subject: TCPCT part 1b: generate Responder Cookie secret Define (missing) hash message size for SHA1. Define hashing size constants specific to TCP cookies. Add new function: tcp_cookie_generator(). Maintain global secret values for tcp_cookie_generator(). This is a significantly revised implementation of earlier (15-year-old) Photuris [RFC-2522] code for the KA9Q cooperative multitasking platform. Linux RCU technique appears to be well-suited to this application, though neither of the circular queue items are freed. These functions will also be used in subsequent patches that implement additional features. Signed-off-by: William.Allen.Simpson@gmail.com Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/cryptohash.h | 1 + include/net/tcp.h | 8 +++ net/ipv4/tcp.c | 140 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) (limited to 'net') diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h index c118b2ad980..ec78a4bbe1d 100644 --- a/include/linux/cryptohash.h +++ b/include/linux/cryptohash.h @@ -2,6 +2,7 @@ #define __CRYPTOHASH_H #define SHA_DIGEST_WORDS 5 +#define SHA_MESSAGE_BYTES (512 /*bits*/ / 8) #define SHA_WORKSPACE_WORDS 80 void sha_init(__u32 *buf); diff --git a/include/net/tcp.h b/include/net/tcp.h index ec183fda05d..4a99a8e3912 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1478,6 +1478,14 @@ struct tcp_request_sock_ops { #endif }; +/* Using SHA1 for now, define some constants. + */ +#define COOKIE_DIGEST_WORDS (SHA_DIGEST_WORDS) +#define COOKIE_MESSAGE_WORDS (SHA_MESSAGE_BYTES / 4) +#define COOKIE_WORKSPACE_WORDS (COOKIE_DIGEST_WORDS + COOKIE_MESSAGE_WORDS) + +extern int tcp_cookie_generator(u32 *bakery); + extern void tcp_v4_init(void); extern void tcp_init(void); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7d4648f8b3d..ba03ac80435 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -264,6 +264,7 @@ #include #include #include +#include #include #include @@ -2848,6 +2849,135 @@ EXPORT_SYMBOL(tcp_md5_hash_key); #endif +/** + * Each Responder maintains up to two secret values concurrently for + * efficient secret rollover. Each secret value has 4 states: + * + * Generating. (tcp_secret_generating != tcp_secret_primary) + * Generates new Responder-Cookies, but not yet used for primary + * verification. This is a short-term state, typically lasting only + * one round trip time (RTT). + * + * Primary. (tcp_secret_generating == tcp_secret_primary) + * Used both for generation and primary verification. + * + * Retiring. (tcp_secret_retiring != tcp_secret_secondary) + * Used for verification, until the first failure that can be + * verified by the newer Generating secret. At that time, this + * cookie's state is changed to Secondary, and the Generating + * cookie's state is changed to Primary. This is a short-term state, + * typically lasting only one round trip time (RTT). + * + * Secondary. (tcp_secret_retiring == tcp_secret_secondary) + * Used for secondary verification, after primary verification + * failures. This state lasts no more than twice the Maximum Segment + * Lifetime (2MSL). Then, the secret is discarded. + */ +struct tcp_cookie_secret { + /* The secret is divided into two parts. The digest part is the + * equivalent of previously hashing a secret and saving the state, + * and serves as an initialization vector (IV). The message part + * serves as the trailing secret. + */ + u32 secrets[COOKIE_WORKSPACE_WORDS]; + unsigned long expires; +}; + +#define TCP_SECRET_1MSL (HZ * TCP_PAWS_MSL) +#define TCP_SECRET_2MSL (HZ * TCP_PAWS_MSL * 2) +#define TCP_SECRET_LIFE (HZ * 600) + +static struct tcp_cookie_secret tcp_secret_one; +static struct tcp_cookie_secret tcp_secret_two; + +/* Essentially a circular list, without dynamic allocation. */ +static struct tcp_cookie_secret *tcp_secret_generating; +static struct tcp_cookie_secret *tcp_secret_primary; +static struct tcp_cookie_secret *tcp_secret_retiring; +static struct tcp_cookie_secret *tcp_secret_secondary; + +static DEFINE_SPINLOCK(tcp_secret_locker); + +/* Select a pseudo-random word in the cookie workspace. + */ +static inline u32 tcp_cookie_work(const u32 *ws, const int n) +{ + return ws[COOKIE_DIGEST_WORDS + ((COOKIE_MESSAGE_WORDS-1) & ws[n])]; +} + +/* Fill bakery[COOKIE_WORKSPACE_WORDS] with generator, updating as needed. + * Called in softirq context. + * Returns: 0 for success. + */ +int tcp_cookie_generator(u32 *bakery) +{ + unsigned long jiffy = jiffies; + + if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) { + spin_lock_bh(&tcp_secret_locker); + if (!time_after_eq(jiffy, tcp_secret_generating->expires)) { + /* refreshed by another */ + memcpy(bakery, + &tcp_secret_generating->secrets[0], + COOKIE_WORKSPACE_WORDS); + } else { + /* still needs refreshing */ + get_random_bytes(bakery, COOKIE_WORKSPACE_WORDS); + + /* The first time, paranoia assumes that the + * randomization function isn't as strong. But, + * this secret initialization is delayed until + * the last possible moment (packet arrival). + * Although that time is observable, it is + * unpredictably variable. Mash in the most + * volatile clock bits available, and expire the + * secret extra quickly. + */ + if (unlikely(tcp_secret_primary->expires == + tcp_secret_secondary->expires)) { + struct timespec tv; + + getnstimeofday(&tv); + bakery[COOKIE_DIGEST_WORDS+0] ^= + (u32)tv.tv_nsec; + + tcp_secret_secondary->expires = jiffy + + TCP_SECRET_1MSL + + (0x0f & tcp_cookie_work(bakery, 0)); + } else { + tcp_secret_secondary->expires = jiffy + + TCP_SECRET_LIFE + + (0xff & tcp_cookie_work(bakery, 1)); + tcp_secret_primary->expires = jiffy + + TCP_SECRET_2MSL + + (0x1f & tcp_cookie_work(bakery, 2)); + } + memcpy(&tcp_secret_secondary->secrets[0], + bakery, COOKIE_WORKSPACE_WORDS); + + rcu_assign_pointer(tcp_secret_generating, + tcp_secret_secondary); + rcu_assign_pointer(tcp_secret_retiring, + tcp_secret_primary); + /* + * Neither call_rcu() nor synchronize_rcu() needed. + * Retiring data is not freed. It is replaced after + * further (locked) pointer updates, and a quiet time + * (minimum 1MSL, maximum LIFE - 2MSL). + */ + } + spin_unlock_bh(&tcp_secret_locker); + } else { + rcu_read_lock_bh(); + memcpy(bakery, + &rcu_dereference(tcp_secret_generating)->secrets[0], + COOKIE_WORKSPACE_WORDS); + rcu_read_unlock_bh(); + } + return 0; +} +EXPORT_SYMBOL(tcp_cookie_generator); + void tcp_done(struct sock *sk) { if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) @@ -2882,6 +3012,7 @@ void __init tcp_init(void) struct sk_buff *skb = NULL; unsigned long nr_pages, limit; int order, i, max_share; + unsigned long jiffy = jiffies; BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); @@ -2975,6 +3106,15 @@ void __init tcp_init(void) tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); tcp_register_congestion_control(&tcp_reno); + + memset(&tcp_secret_one.secrets[0], 0, sizeof(tcp_secret_one.secrets)); + memset(&tcp_secret_two.secrets[0], 0, sizeof(tcp_secret_two.secrets)); + tcp_secret_one.expires = jiffy; /* past due */ + tcp_secret_two.expires = jiffy; /* past due */ + tcp_secret_generating = &tcp_secret_one; + tcp_secret_primary = &tcp_secret_one; + tcp_secret_retiring = &tcp_secret_two; + tcp_secret_secondary = &tcp_secret_two; } EXPORT_SYMBOL(tcp_close); -- cgit v1.2.3 From 519855c508b9a17878c0977a3cdefc09b59b30df Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Wed, 2 Dec 2009 18:14:19 +0000 Subject: TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS Define sysctl (tcp_cookie_size) to turn on and off the cookie option default globally, instead of a compiled configuration option. Define per socket option (TCP_COOKIE_TRANSACTIONS) for setting constant data values, retrieving variable cookie values, and other facilities. Move inline tcp_clear_options() unchanged from net/tcp.h to linux/tcp.h, near its corresponding struct tcp_options_received (prior to changes). This is a straightforward re-implementation of an earlier (year-old) patch that no longer applies cleanly, with permission of the original author (Adam Langley): http://thread.gmane.org/gmane.linux.network/102586 These functions will also be used in subsequent patches that implement additional features. Requires: net: TCP_MSS_DEFAULT, TCP_MSS_DESIRED Signed-off-by: William.Allen.Simpson@gmail.com Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 8 ++++++++ include/linux/tcp.h | 33 ++++++++++++++++++++++++++++++++- include/net/tcp.h | 6 +----- net/ipv4/sysctl_net_ipv4.c | 8 ++++++++ net/ipv4/tcp_output.c | 3 +++ 5 files changed, 52 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 554440af675..989f5538b8d 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -164,6 +164,14 @@ tcp_congestion_control - STRING additional choices may be available based on kernel configuration. Default is set as part of kernel configuration. +tcp_cookie_size - INTEGER + Default size of TCP Cookie Transactions (TCPCT) option, that may be + overridden on a per socket basis by the TCPCT socket option. + Values greater than the maximum (16) are interpreted as the maximum. + Values greater than zero and less than the minimum (8) are interpreted + as the minimum. Odd values are interpreted as the next even value. + Default: 0 (off). + tcp_dsack - BOOLEAN Allows TCP to send "duplicate" SACKs. diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 32d7d77b4a0..eaa3113b378 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -102,7 +102,9 @@ enum { #define TCP_QUICKACK 12 /* Block/reenable quick acks */ #define TCP_CONGESTION 13 /* Congestion control algorithm */ #define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */ +#define TCP_COOKIE_TRANSACTIONS 15 /* TCP Cookie Transactions */ +/* for TCP_INFO socket option */ #define TCPI_OPT_TIMESTAMPS 1 #define TCPI_OPT_SACK 2 #define TCPI_OPT_WSCALE 4 @@ -174,6 +176,30 @@ struct tcp_md5sig { __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ }; +/* for TCP_COOKIE_TRANSACTIONS (TCPCT) socket option */ +#define TCP_COOKIE_MIN 8 /* 64-bits */ +#define TCP_COOKIE_MAX 16 /* 128-bits */ +#define TCP_COOKIE_PAIR_SIZE (2*TCP_COOKIE_MAX) + +/* Flags for both getsockopt and setsockopt */ +#define TCP_COOKIE_IN_ALWAYS (1 << 0) /* Discard SYN without cookie */ +#define TCP_COOKIE_OUT_NEVER (1 << 1) /* Prohibit outgoing cookies, + * supercedes everything. */ + +/* Flags for getsockopt */ +#define TCP_S_DATA_IN (1 << 2) /* Was data received? */ +#define TCP_S_DATA_OUT (1 << 3) /* Was data sent? */ + +/* TCP_COOKIE_TRANSACTIONS data */ +struct tcp_cookie_transactions { + __u16 tcpct_flags; /* see above */ + __u8 __tcpct_pad1; /* zero */ + __u8 tcpct_cookie_desired; /* bytes */ + __u16 tcpct_s_data_desired; /* bytes of variable data */ + __u16 tcpct_used; /* bytes in value */ + __u8 tcpct_value[TCP_MSS_DEFAULT]; +}; + #ifdef __KERNEL__ #include @@ -227,6 +253,11 @@ struct tcp_options_received { u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ }; +static inline void tcp_clear_options(struct tcp_options_received *rx_opt) +{ + rx_opt->tstamp_ok = rx_opt->sack_ok = rx_opt->wscale_ok = rx_opt->snd_wscale = 0; +} + /* This is the max number of SACKS that we'll generate and process. It's safe * to increse this, although since: * size = TCPOLEN_SACK_BASE_ALIGNED (4) + n * TCPOLEN_SACK_PERBLOCK (8) @@ -435,6 +466,6 @@ static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) return (struct tcp_timewait_sock *)sk; } -#endif +#endif /* __KERNEL__ */ #endif /* _LINUX_TCP_H */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 4a99a8e3912..738b65f01e2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -234,6 +234,7 @@ extern int sysctl_tcp_base_mss; extern int sysctl_tcp_workaround_signed_windows; extern int sysctl_tcp_slow_start_after_idle; extern int sysctl_tcp_max_ssthresh; +extern int sysctl_tcp_cookie_size; extern atomic_t tcp_memory_allocated; extern struct percpu_counter tcp_sockets_allocated; @@ -340,11 +341,6 @@ static inline void tcp_dec_quickack_mode(struct sock *sk, extern void tcp_enter_quickack_mode(struct sock *sk); -static inline void tcp_clear_options(struct tcp_options_received *rx_opt) -{ - rx_opt->tstamp_ok = rx_opt->sack_ok = rx_opt->wscale_ok = rx_opt->snd_wscale = 0; -} - #define TCP_ECN_OK 1 #define TCP_ECN_QUEUE_CWR 2 #define TCP_ECN_DEMAND_CWR 4 diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c00323bae04..13f7ab6ad6a 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -712,6 +712,14 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "tcp_cookie_size", + .data = &sysctl_tcp_cookie_size, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { .ctl_name = CTL_UNNUMBERED, .procname = "udp_mem", diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b8b25049f25..307f318fe93 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -59,6 +59,9 @@ int sysctl_tcp_base_mss __read_mostly = 512; /* By default, RFC2861 behavior. */ int sysctl_tcp_slow_start_after_idle __read_mostly = 1; +int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */ + + /* Account for new data that has been sent to the network. */ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) { -- cgit v1.2.3 From 435cf559f02ea3a3159eb316f97dc88bdebe9432 Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Wed, 2 Dec 2009 18:17:05 +0000 Subject: TCPCT part 1d: define TCP cookie option, extend existing struct's Data structures are carefully composed to require minimal additions. For example, the struct tcp_options_received cookie_plus variable fits between existing 16-bit and 8-bit variables, requiring no additional space (taking alignment into consideration). There are no additions to tcp_request_sock, and only 1 pointer in tcp_sock. This is a significantly revised implementation of an earlier (year-old) patch that no longer applies cleanly, with permission of the original author (Adam Langley): http://thread.gmane.org/gmane.linux.network/102586 The principle difference is using a TCP option to carry the cookie nonce, instead of a user configured offset in the data. This is more flexible and less subject to user configuration error. Such a cookie option has been suggested for many years, and is also useful without SYN data, allowing several related concepts to use the same extension option. "Re: SYN floods (was: does history repeat itself?)", September 9, 1996. http://www.merit.net/mail.archives/nanog/1996-09/msg00235.html "Re: what a new TCP header might look like", May 12, 1998. ftp://ftp.isi.edu/end2end/end2end-interest-1998.mail These functions will also be used in subsequent patches that implement additional features. Requires: TCPCT part 1a: add request_values parameter for sending SYNACK TCPCT part 1b: generate Responder Cookie secret TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS Signed-off-by: William.Allen.Simpson@gmail.com Signed-off-by: David S. Miller --- include/linux/tcp.h | 29 +++++++++++++---- include/net/tcp.h | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_ipv4.c | 20 ++++++++++++ net/ipv4/tcp_minisocks.c | 46 ++++++++++++++++++++++----- net/ipv6/tcp_ipv6.c | 13 ++++++++ 5 files changed, 177 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index eaa3113b378..7fee8a4df93 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -247,31 +247,38 @@ struct tcp_options_received { sack_ok : 4, /* SACK seen on SYN packet */ snd_wscale : 4, /* Window scaling received from sender */ rcv_wscale : 4; /* Window scaling to send to receiver */ -/* SACKs data */ + u8 cookie_plus:6, /* bytes in authenticator/cookie option */ + cookie_out_never:1, + cookie_in_always:1; u8 num_sacks; /* Number of SACK blocks */ - u16 user_mss; /* mss requested by user in ioctl */ + u16 user_mss; /* mss requested by user in ioctl */ u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ }; static inline void tcp_clear_options(struct tcp_options_received *rx_opt) { - rx_opt->tstamp_ok = rx_opt->sack_ok = rx_opt->wscale_ok = rx_opt->snd_wscale = 0; + rx_opt->tstamp_ok = rx_opt->sack_ok = 0; + rx_opt->wscale_ok = rx_opt->snd_wscale = 0; + rx_opt->cookie_plus = 0; } /* This is the max number of SACKS that we'll generate and process. It's safe - * to increse this, although since: + * to increase this, although since: * size = TCPOLEN_SACK_BASE_ALIGNED (4) + n * TCPOLEN_SACK_PERBLOCK (8) * only four options will fit in a standard TCP header */ #define TCP_NUM_SACKS 4 +struct tcp_cookie_values; +struct tcp_request_sock_ops; + struct tcp_request_sock { struct inet_request_sock req; #ifdef CONFIG_TCP_MD5SIG /* Only used by TCP MD5 Signature so far. */ const struct tcp_request_sock_ops *af_specific; #endif - u32 rcv_isn; - u32 snt_isn; + u32 rcv_isn; + u32 snt_isn; }; static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) @@ -441,6 +448,12 @@ struct tcp_sock { /* TCP MD5 Signature Option information */ struct tcp_md5sig_info *md5sig_info; #endif + + /* When the cookie options are generated and exchanged, then this + * object holds a reference to them (cookie_values->kref). Also + * contains related tcp_cookie_transactions fields. + */ + struct tcp_cookie_values *cookie_values; }; static inline struct tcp_sock *tcp_sk(const struct sock *sk) @@ -459,6 +472,10 @@ struct tcp_timewait_sock { u16 tw_md5_keylen; u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; #endif + /* Few sockets in timewait have cookies; in that case, then this + * object holds a reference to them (tw_cookie_values->kref). + */ + struct tcp_cookie_values *tw_cookie_values; }; static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) diff --git a/include/net/tcp.h b/include/net/tcp.h index 738b65f01e2..f9abd9becab 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -164,6 +165,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOPT_SACK 5 /* SACK Block */ #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ +#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */ /* * TCP option lengths @@ -174,6 +176,10 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_SACK_PERM 2 #define TCPOLEN_TIMESTAMP 10 #define TCPOLEN_MD5SIG 18 +#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */ +#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */ +#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN) +#define TCPOLEN_COOKIE_MAX (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX) /* But this is what stacks really send out. */ #define TCPOLEN_TSTAMP_ALIGNED 12 @@ -1482,6 +1488,83 @@ struct tcp_request_sock_ops { extern int tcp_cookie_generator(u32 *bakery); +/** + * struct tcp_cookie_values - each socket needs extra space for the + * cookies, together with (optional) space for any SYN data. + * + * A tcp_sock contains a pointer to the current value, and this is + * cloned to the tcp_timewait_sock. + * + * @cookie_pair: variable data from the option exchange. + * + * @cookie_desired: user specified tcpct_cookie_desired. Zero + * indicates default (sysctl_tcp_cookie_size). + * After cookie sent, remembers size of cookie. + * Range 0, TCP_COOKIE_MIN to TCP_COOKIE_MAX. + * + * @s_data_desired: user specified tcpct_s_data_desired. When the + * constant payload is specified (@s_data_constant), + * holds its length instead. + * Range 0 to TCP_MSS_DESIRED. + * + * @s_data_payload: constant data that is to be included in the + * payload of SYN or SYNACK segments when the + * cookie option is present. + */ +struct tcp_cookie_values { + struct kref kref; + u8 cookie_pair[TCP_COOKIE_PAIR_SIZE]; + u8 cookie_pair_size; + u8 cookie_desired; + u16 s_data_desired:11, + s_data_constant:1, + s_data_in:1, + s_data_out:1, + s_data_unused:2; + u8 s_data_payload[0]; +}; + +static inline void tcp_cookie_values_release(struct kref *kref) +{ + kfree(container_of(kref, struct tcp_cookie_values, kref)); +} + +/* The length of constant payload data. Note that s_data_desired is + * overloaded, depending on s_data_constant: either the length of constant + * data (returned here) or the limit on variable data. + */ +static inline int tcp_s_data_size(const struct tcp_sock *tp) +{ + return (tp->cookie_values != NULL && tp->cookie_values->s_data_constant) + ? tp->cookie_values->s_data_desired + : 0; +} + +/** + * struct tcp_extend_values - tcp_ipv?.c to tcp_output.c workspace. + * + * As tcp_request_sock has already been extended in other places, the + * only remaining method is to pass stack values along as function + * parameters. These parameters are not needed after sending SYNACK. + * + * @cookie_bakery: cryptographic secret and message workspace. + * + * @cookie_plus: bytes in authenticator/cookie option, copied from + * struct tcp_options_received (above). + */ +struct tcp_extend_values { + struct request_values rv; + u32 cookie_bakery[COOKIE_WORKSPACE_WORDS]; + u8 cookie_plus:6, + cookie_out_never:1, + cookie_in_always:1; +}; + +static inline struct tcp_extend_values *tcp_xv(struct request_values *rvp) +{ + return (struct tcp_extend_values *)rvp; +} + extern void tcp_v4_init(void); extern void tcp_init(void); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 649a36d99c7..a2bcac9b388 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1833,6 +1833,19 @@ static int tcp_v4_init_sock(struct sock *sk) tp->af_specific = &tcp_sock_ipv4_specific; #endif + /* TCP Cookie Transactions */ + if (sysctl_tcp_cookie_size > 0) { + /* Default, cookies without s_data_payload. */ + tp->cookie_values = + kzalloc(sizeof(*tp->cookie_values), + sk->sk_allocation); + if (tp->cookie_values != NULL) + kref_init(&tp->cookie_values->kref); + } + /* Presumed zeroed, in order of appearance: + * cookie_in_always, cookie_out_never, + * s_data_constant, s_data_in, s_data_out + */ sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; @@ -1886,6 +1899,13 @@ void tcp_v4_destroy_sock(struct sock *sk) sk->sk_sndmsg_page = NULL; } + /* TCP Cookie Transactions */ + if (tp->cookie_values != NULL) { + kref_put(&tp->cookie_values->kref, + tcp_cookie_values_release); + tp->cookie_values = NULL; + } + percpu_counter_dec(&tcp_sockets_allocated); } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index d3f6bbfc76f..96852af43ca 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -383,14 +383,43 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, const struct inet_request_sock *ireq = inet_rsk(req); struct tcp_request_sock *treq = tcp_rsk(req); struct inet_connection_sock *newicsk = inet_csk(newsk); - struct tcp_sock *newtp; + struct tcp_sock *newtp = tcp_sk(newsk); + struct tcp_sock *oldtp = tcp_sk(sk); + struct tcp_cookie_values *oldcvp = oldtp->cookie_values; + + /* TCP Cookie Transactions require space for the cookie pair, + * as it differs for each connection. There is no need to + * copy any s_data_payload stored at the original socket. + * Failure will prevent resuming the connection. + * + * Presumed copied, in order of appearance: + * cookie_in_always, cookie_out_never + */ + if (oldcvp != NULL) { + struct tcp_cookie_values *newcvp = + kzalloc(sizeof(*newtp->cookie_values), + GFP_ATOMIC); + + if (newcvp != NULL) { + kref_init(&newcvp->kref); + newcvp->cookie_desired = + oldcvp->cookie_desired; + newtp->cookie_values = newcvp; + } else { + /* Not Yet Implemented */ + newtp->cookie_values = NULL; + } + } /* Now setup tcp_sock */ - newtp = tcp_sk(newsk); newtp->pred_flags = 0; - newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1; - newtp->snd_sml = newtp->snd_una = newtp->snd_nxt = treq->snt_isn + 1; - newtp->snd_up = treq->snt_isn + 1; + + newtp->rcv_wup = newtp->copied_seq = + newtp->rcv_nxt = treq->rcv_isn + 1; + + newtp->snd_sml = newtp->snd_una = + newtp->snd_nxt = newtp->snd_up = + treq->snt_isn + 1 + tcp_s_data_size(oldtp); tcp_prequeue_init(newtp); @@ -423,8 +452,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, tcp_set_ca_state(newsk, TCP_CA_Open); tcp_init_xmit_timers(newsk); skb_queue_head_init(&newtp->out_of_order_queue); - newtp->write_seq = treq->snt_isn + 1; - newtp->pushed_seq = newtp->write_seq; + newtp->write_seq = newtp->pushed_seq = + treq->snt_isn + 1 + tcp_s_data_size(oldtp); newtp->rx_opt.saw_tstamp = 0; @@ -590,7 +619,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * Invalid ACK: reset will be sent by listening socket */ if ((flg & TCP_FLAG_ACK) && - (TCP_SKB_CB(skb)->ack_seq != tcp_rsk(req)->snt_isn + 1)) + (TCP_SKB_CB(skb)->ack_seq != + tcp_rsk(req)->snt_isn + 1 + tcp_s_data_size(tcp_sk(sk)))) return sk; /* Also, it would be not so bad idea to check rcv_tsecr, which diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index da6e24416d7..f2ec38289a4 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1864,6 +1864,19 @@ static int tcp_v6_init_sock(struct sock *sk) tp->af_specific = &tcp_sock_ipv6_specific; #endif + /* TCP Cookie Transactions */ + if (sysctl_tcp_cookie_size > 0) { + /* Default, cookies without s_data_payload. */ + tp->cookie_values = + kzalloc(sizeof(*tp->cookie_values), + sk->sk_allocation); + if (tp->cookie_values != NULL) + kref_init(&tp->cookie_values->kref); + } + /* Presumed zeroed, in order of appearance: + * cookie_in_always, cookie_out_never, + * s_data_constant, s_data_in, s_data_out + */ sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; -- cgit v1.2.3 From e56fb50f2b7958b931c8a2fc0966061b3f3c8f3a Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Wed, 2 Dec 2009 18:19:30 +0000 Subject: TCPCT part 1e: implement socket option TCP_COOKIE_TRANSACTIONS Provide per socket control of the TCP cookie option and SYN/SYNACK data. This is a straightforward re-implementation of an earlier (year-old) patch that no longer applies cleanly, with permission of the original author (Adam Langley): http://thread.gmane.org/gmane.linux.network/102586 The principle difference is using a TCP option to carry the cookie nonce, instead of a user configured offset in the data. Allocations have been rearranged to avoid requiring GFP_ATOMIC. Requires: net: TCP_MSS_DEFAULT, TCP_MSS_DESIRED TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS TCPCT part 1d: define TCP cookie option, extend existing struct's Signed-off-by: William.Allen.Simpson@gmail.com Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ba03ac80435..c8666b70cde 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2085,8 +2085,9 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int val; int err = 0; - /* This is a string value all the others are int's */ - if (optname == TCP_CONGESTION) { + /* These are data/string values, all the others are ints */ + switch (optname) { + case TCP_CONGESTION: { char name[TCP_CA_NAME_MAX]; if (optlen < 1) @@ -2103,6 +2104,93 @@ static int do_tcp_setsockopt(struct sock *sk, int level, release_sock(sk); return err; } + case TCP_COOKIE_TRANSACTIONS: { + struct tcp_cookie_transactions ctd; + struct tcp_cookie_values *cvp = NULL; + + if (sizeof(ctd) > optlen) + return -EINVAL; + if (copy_from_user(&ctd, optval, sizeof(ctd))) + return -EFAULT; + + if (ctd.tcpct_used > sizeof(ctd.tcpct_value) || + ctd.tcpct_s_data_desired > TCP_MSS_DESIRED) + return -EINVAL; + + if (ctd.tcpct_cookie_desired == 0) { + /* default to global value */ + } else if ((0x1 & ctd.tcpct_cookie_desired) || + ctd.tcpct_cookie_desired > TCP_COOKIE_MAX || + ctd.tcpct_cookie_desired < TCP_COOKIE_MIN) { + return -EINVAL; + } + + if (TCP_COOKIE_OUT_NEVER & ctd.tcpct_flags) { + /* Supercedes all other values */ + lock_sock(sk); + if (tp->cookie_values != NULL) { + kref_put(&tp->cookie_values->kref, + tcp_cookie_values_release); + tp->cookie_values = NULL; + } + tp->rx_opt.cookie_in_always = 0; /* false */ + tp->rx_opt.cookie_out_never = 1; /* true */ + release_sock(sk); + return err; + } + + /* Allocate ancillary memory before locking. + */ + if (ctd.tcpct_used > 0 || + (tp->cookie_values == NULL && + (sysctl_tcp_cookie_size > 0 || + ctd.tcpct_cookie_desired > 0 || + ctd.tcpct_s_data_desired > 0))) { + cvp = kzalloc(sizeof(*cvp) + ctd.tcpct_used, + GFP_KERNEL); + if (cvp == NULL) + return -ENOMEM; + } + lock_sock(sk); + tp->rx_opt.cookie_in_always = + (TCP_COOKIE_IN_ALWAYS & ctd.tcpct_flags); + tp->rx_opt.cookie_out_never = 0; /* false */ + + if (tp->cookie_values != NULL) { + if (cvp != NULL) { + /* Changed values are recorded by a changed + * pointer, ensuring the cookie will differ, + * without separately hashing each value later. + */ + kref_put(&tp->cookie_values->kref, + tcp_cookie_values_release); + kref_init(&cvp->kref); + tp->cookie_values = cvp; + } else { + cvp = tp->cookie_values; + } + } + if (cvp != NULL) { + cvp->cookie_desired = ctd.tcpct_cookie_desired; + + if (ctd.tcpct_used > 0) { + memcpy(cvp->s_data_payload, ctd.tcpct_value, + ctd.tcpct_used); + cvp->s_data_desired = ctd.tcpct_used; + cvp->s_data_constant = 1; /* true */ + } else { + /* No constant payload data. */ + cvp->s_data_desired = ctd.tcpct_s_data_desired; + cvp->s_data_constant = 0; /* false */ + } + } + release_sock(sk); + return err; + } + default: + /* fallthru */ + break; + }; if (optlen < sizeof(int)) return -EINVAL; @@ -2427,6 +2515,47 @@ static int do_tcp_getsockopt(struct sock *sk, int level, if (copy_to_user(optval, icsk->icsk_ca_ops->name, len)) return -EFAULT; return 0; + + case TCP_COOKIE_TRANSACTIONS: { + struct tcp_cookie_transactions ctd; + struct tcp_cookie_values *cvp = tp->cookie_values; + + if (get_user(len, optlen)) + return -EFAULT; + if (len < sizeof(ctd)) + return -EINVAL; + + memset(&ctd, 0, sizeof(ctd)); + ctd.tcpct_flags = (tp->rx_opt.cookie_in_always ? + TCP_COOKIE_IN_ALWAYS : 0) + | (tp->rx_opt.cookie_out_never ? + TCP_COOKIE_OUT_NEVER : 0); + + if (cvp != NULL) { + ctd.tcpct_flags |= (cvp->s_data_in ? + TCP_S_DATA_IN : 0) + | (cvp->s_data_out ? + TCP_S_DATA_OUT : 0); + + ctd.tcpct_cookie_desired = cvp->cookie_desired; + ctd.tcpct_s_data_desired = cvp->s_data_desired; + + /* Cookie(s) saved, return as nonce */ + if (sizeof(ctd.tcpct_value) < cvp->cookie_pair_size) { + /* impossible? */ + return -EINVAL; + } + memcpy(&ctd.tcpct_value[0], &cvp->cookie_pair[0], + cvp->cookie_pair_size); + ctd.tcpct_used = cvp->cookie_pair_size; + } + + if (put_user(sizeof(ctd), optlen)) + return -EFAULT; + if (copy_to_user(optval, &ctd, sizeof(ctd))) + return -EFAULT; + return 0; + } default: return -ENOPROTOOPT; } -- cgit v1.2.3 From bd0388ae77075026d6a9f9eb6026dfd1d52ce0e9 Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Wed, 2 Dec 2009 18:23:05 +0000 Subject: TCPCT part 1f: Initiator Cookie => Responder Calculate and format TCP_COOKIE option. This is a significantly revised implementation of an earlier (year-old) patch that no longer applies cleanly, with permission of the original author (Adam Langley): http://thread.gmane.org/gmane.linux.network/102586 Requires: TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS TCPCT part 1d: define TCP cookie option, extend existing struct's Signed-off-by: William.Allen.Simpson@gmail.com Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 193 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 163 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 307f318fe93..35dd983a8a9 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -365,15 +365,45 @@ static inline int tcp_urg_mode(const struct tcp_sock *tp) #define OPTION_TS (1 << 1) #define OPTION_MD5 (1 << 2) #define OPTION_WSCALE (1 << 3) +#define OPTION_COOKIE_EXTENSION (1 << 4) struct tcp_out_options { u8 options; /* bit field of OPTION_* */ u8 ws; /* window scale, 0 to disable */ u8 num_sack_blocks; /* number of SACK blocks to include */ + u8 hash_size; /* bytes in hash_location */ u16 mss; /* 0 to disable */ __u32 tsval, tsecr; /* need to include OPTION_TS */ + __u8 *hash_location; /* temporary pointer, overloaded */ }; +/* The sysctl int routines are generic, so check consistency here. + */ +static u8 tcp_cookie_size_check(u8 desired) +{ + if (desired > 0) { + /* previously specified */ + return desired; + } + if (sysctl_tcp_cookie_size <= 0) { + /* no default specified */ + return 0; + } + if (sysctl_tcp_cookie_size <= TCP_COOKIE_MIN) { + /* value too small, specify minimum */ + return TCP_COOKIE_MIN; + } + if (sysctl_tcp_cookie_size >= TCP_COOKIE_MAX) { + /* value too large, specify maximum */ + return TCP_COOKIE_MAX; + } + if (0x1 & sysctl_tcp_cookie_size) { + /* 8-bit multiple, illegal, fix it */ + return (u8)(sysctl_tcp_cookie_size + 0x1); + } + return (u8)sysctl_tcp_cookie_size; +} + /* Write previously computed TCP options to the packet. * * Beware: Something in the Internet is very sensitive to the ordering of @@ -388,17 +418,34 @@ struct tcp_out_options { * (but it may well be that other scenarios fail similarly). */ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, - const struct tcp_out_options *opts, - __u8 **md5_hash) { - if (unlikely(OPTION_MD5 & opts->options)) { - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_MD5SIG << 8) | - TCPOLEN_MD5SIG); - *md5_hash = (__u8 *)ptr; + struct tcp_out_options *opts) +{ + u8 options = opts->options; /* mungable copy */ + + /* Having both authentication and cookies for security is redundant, + * and there's certainly not enough room. Instead, the cookie-less + * extension variant is proposed. + * + * Consider the pessimal case with authentication. The options + * could look like: + * COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40 + */ + if (unlikely(OPTION_MD5 & options)) { + if (unlikely(OPTION_COOKIE_EXTENSION & options)) { + *ptr++ = htonl((TCPOPT_COOKIE << 24) | + (TCPOLEN_COOKIE_BASE << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + } else { + *ptr++ = htonl((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_MD5SIG << 8) | + TCPOLEN_MD5SIG); + } + options &= ~OPTION_COOKIE_EXTENSION; + /* overload cookie hash location */ + opts->hash_location = (__u8 *)ptr; ptr += 4; - } else { - *md5_hash = NULL; } if (unlikely(opts->mss)) { @@ -407,12 +454,13 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, opts->mss); } - if (likely(OPTION_TS & opts->options)) { - if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) { + if (likely(OPTION_TS & options)) { + if (unlikely(OPTION_SACK_ADVERTISE & options)) { *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); + options &= ~OPTION_SACK_ADVERTISE; } else { *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -423,15 +471,52 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, *ptr++ = htonl(opts->tsecr); } - if (unlikely(OPTION_SACK_ADVERTISE & opts->options && - !(OPTION_TS & opts->options))) { + /* Specification requires after timestamp, so do it now. + * + * Consider the pessimal case without authentication. The options + * could look like: + * MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40 + */ + if (unlikely(OPTION_COOKIE_EXTENSION & options)) { + __u8 *cookie_copy = opts->hash_location; + u8 cookie_size = opts->hash_size; + + /* 8-bit multiple handled in tcp_cookie_size_check() above, + * and elsewhere. + */ + if (0x2 & cookie_size) { + __u8 *p = (__u8 *)ptr; + + /* 16-bit multiple */ + *p++ = TCPOPT_COOKIE; + *p++ = TCPOLEN_COOKIE_BASE + cookie_size; + *p++ = *cookie_copy++; + *p++ = *cookie_copy++; + ptr++; + cookie_size -= 2; + } else { + /* 32-bit multiple */ + *ptr++ = htonl(((TCPOPT_NOP << 24) | + (TCPOPT_NOP << 16) | + (TCPOPT_COOKIE << 8) | + TCPOLEN_COOKIE_BASE) + + cookie_size); + } + + if (cookie_size > 0) { + memcpy(ptr, cookie_copy, cookie_size); + ptr += (cookie_size / 4); + } + } + + if (unlikely(OPTION_SACK_ADVERTISE & options)) { *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM); } - if (unlikely(OPTION_WSCALE & opts->options)) { + if (unlikely(OPTION_WSCALE & options)) { *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | @@ -466,14 +551,18 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, struct tcp_out_options *opts, struct tcp_md5sig_key **md5) { struct tcp_sock *tp = tcp_sk(sk); - unsigned size = 0; + struct tcp_cookie_values *cvp = tp->cookie_values; struct dst_entry *dst = __sk_dst_get(sk); + unsigned remaining = MAX_TCP_OPTION_SPACE; + u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL) ? + tcp_cookie_size_check(cvp->cookie_desired) : + 0; #ifdef CONFIG_TCP_MD5SIG *md5 = tp->af_specific->md5_lookup(sk, sk); if (*md5) { opts->options |= OPTION_MD5; - size += TCPOLEN_MD5SIG_ALIGNED; + remaining -= TCPOLEN_MD5SIG_ALIGNED; } #else *md5 = NULL; @@ -489,7 +578,7 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, * SACKs don't matter, we never delay an ACK when we have any of those * going out. */ opts->mss = tcp_advertise_mss(sk); - size += TCPOLEN_MSS_ALIGNED; + remaining -= TCPOLEN_MSS_ALIGNED; if (likely(sysctl_tcp_timestamps && !dst_feature(dst, RTAX_FEATURE_NO_TSTAMP) && @@ -497,22 +586,68 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, opts->options |= OPTION_TS; opts->tsval = TCP_SKB_CB(skb)->when; opts->tsecr = tp->rx_opt.ts_recent; - size += TCPOLEN_TSTAMP_ALIGNED; + remaining -= TCPOLEN_TSTAMP_ALIGNED; } if (likely(sysctl_tcp_window_scaling && !dst_feature(dst, RTAX_FEATURE_NO_WSCALE))) { opts->ws = tp->rx_opt.rcv_wscale; opts->options |= OPTION_WSCALE; - size += TCPOLEN_WSCALE_ALIGNED; + remaining -= TCPOLEN_WSCALE_ALIGNED; } if (likely(sysctl_tcp_sack && !dst_feature(dst, RTAX_FEATURE_NO_SACK))) { opts->options |= OPTION_SACK_ADVERTISE; if (unlikely(!(OPTION_TS & opts->options))) - size += TCPOLEN_SACKPERM_ALIGNED; + remaining -= TCPOLEN_SACKPERM_ALIGNED; } - return size; + /* Note that timestamps are required by the specification. + * + * Odd numbers of bytes are prohibited by the specification, ensuring + * that the cookie is 16-bit aligned, and the resulting cookie pair is + * 32-bit aligned. + */ + if (*md5 == NULL && + (OPTION_TS & opts->options) && + cookie_size > 0) { + int need = TCPOLEN_COOKIE_BASE + cookie_size; + + if (0x2 & need) { + /* 32-bit multiple */ + need += 2; /* NOPs */ + + if (need > remaining) { + /* try shrinking cookie to fit */ + cookie_size -= 2; + need -= 4; + } + } + while (need > remaining && TCP_COOKIE_MIN <= cookie_size) { + cookie_size -= 4; + need -= 4; + } + if (TCP_COOKIE_MIN <= cookie_size) { + opts->options |= OPTION_COOKIE_EXTENSION; + opts->hash_location = (__u8 *)&cvp->cookie_pair[0]; + opts->hash_size = cookie_size; + + /* Remember for future incarnations. */ + cvp->cookie_desired = cookie_size; + + if (cvp->cookie_desired != cvp->cookie_pair_size) { + /* Currently use random bytes as a nonce, + * assuming these are completely unpredictable + * by hostile users of the same system. + */ + get_random_bytes(&cvp->cookie_pair[0], + cookie_size); + cvp->cookie_pair_size = cookie_size; + } + + remaining -= need; + } + } + return MAX_TCP_OPTION_SPACE - remaining; } /* Set up TCP options for SYN-ACKs. */ @@ -627,7 +762,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, struct tcp_out_options opts; unsigned tcp_options_size, tcp_header_size; struct tcp_md5sig_key *md5; - __u8 *md5_hash_location; struct tcphdr *th; int err; @@ -698,7 +832,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, } } - tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); + tcp_options_write((__be32 *)(th + 1), tp, &opts); if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0)) TCP_ECN_send(sk, skb, tcp_header_size); @@ -706,7 +840,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, /* Calculate the MD5 hash, as we have all we need now */ if (md5) { sk->sk_route_caps &= ~NETIF_F_GSO_MASK; - tp->af_specific->calc_md5_hash(md5_hash_location, + tp->af_specific->calc_md5_hash(opts.hash_location, md5, sk, NULL, skb); } #endif @@ -2230,14 +2364,13 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct request_sock *req, struct request_values *rvp) { + struct tcp_out_options opts; struct inet_request_sock *ireq = inet_rsk(req); struct tcp_sock *tp = tcp_sk(sk); struct tcphdr *th; - int tcp_header_size; - struct tcp_out_options opts; struct sk_buff *skb; struct tcp_md5sig_key *md5; - __u8 *md5_hash_location; + int tcp_header_size; int mss; skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); @@ -2298,14 +2431,14 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ th->window = htons(min(req->rcv_wnd, 65535U)); - tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); + tcp_options_write((__be32 *)(th + 1), tp, &opts); th->doff = (tcp_header_size >> 2); TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); #ifdef CONFIG_TCP_MD5SIG /* Okay, we have all we need - do the md5 hash if needed */ if (md5) { - tcp_rsk(req)->af_specific->calc_md5_hash(md5_hash_location, + tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location, md5, NULL, req, skb); } #endif -- cgit v1.2.3 From 4957faade11b3a278c3b3cade3411ddc20afa791 Mon Sep 17 00:00:00 2001 From: William Allen Simpson Date: Wed, 2 Dec 2009 18:25:27 +0000 Subject: TCPCT part 1g: Responder Cookie => Initiator Parse incoming TCP_COOKIE option(s). Calculate TCP_COOKIE option. Send optional data. This is a significantly revised implementation of an earlier (year-old) patch that no longer applies cleanly, with permission of the original author (Adam Langley): http://thread.gmane.org/gmane.linux.network/102586 Requires: TCPCT part 1a: add request_values parameter for sending SYNACK TCPCT part 1b: generate Responder Cookie secret TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS TCPCT part 1d: define TCP cookie option, extend existing struct's TCPCT part 1e: implement socket option TCP_COOKIE_TRANSACTIONS TCPCT part 1f: Initiator Cookie => Responder Signed-off-by: William.Allen.Simpson@gmail.com Signed-off-by: David S. Miller --- include/net/tcp.h | 1 + net/ipv4/syncookies.c | 5 ++- net/ipv4/tcp_input.c | 75 +++++++++++++++++++++++++++++----- net/ipv4/tcp_ipv4.c | 47 +++++++++++++++++++-- net/ipv4/tcp_minisocks.c | 14 ++++--- net/ipv4/tcp_output.c | 103 +++++++++++++++++++++++++++++++++++++++-------- net/ipv6/syncookies.c | 5 ++- net/ipv6/tcp_ipv6.c | 52 +++++++++++++++++++++++- 8 files changed, 259 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index f9abd9becab..28b04ff8c96 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -407,6 +407,7 @@ extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, extern void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, + u8 **hvpp, int estab, struct dst_entry *dst); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 3146cc40174..26399ad2a28 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -253,6 +253,8 @@ EXPORT_SYMBOL(cookie_check_timestamp); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt) { + struct tcp_options_received tcp_opt; + u8 *hash_location; struct inet_request_sock *ireq; struct tcp_request_sock *treq; struct tcp_sock *tp = tcp_sk(sk); @@ -263,7 +265,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, int mss; struct rtable *rt; __u8 rcv_wscale; - struct tcp_options_received tcp_opt; if (!sysctl_tcp_syncookies || !th->ack) goto out; @@ -341,7 +342,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, /* check for timestamp cookie support */ memset(&tcp_opt, 0, sizeof(tcp_opt)); - tcp_parse_options(skb, &tcp_opt, 0, &rt->u.dst); + tcp_parse_options(skb, &tcp_opt, &hash_location, 0, &rt->u.dst); if (tcp_opt.saw_tstamp) cookie_check_timestamp(&tcp_opt); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index be166e0e11c..57ae96a0422 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3698,7 +3698,7 @@ old_ack: * the fast version below fails. */ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, - int estab, struct dst_entry *dst) + u8 **hvpp, int estab, struct dst_entry *dst) { unsigned char *ptr; struct tcphdr *th = tcp_hdr(skb); @@ -3785,7 +3785,30 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, */ break; #endif - } + case TCPOPT_COOKIE: + /* This option is variable length. + */ + switch (opsize) { + case TCPOLEN_COOKIE_BASE: + /* not yet implemented */ + break; + case TCPOLEN_COOKIE_PAIR: + /* not yet implemented */ + break; + case TCPOLEN_COOKIE_MIN+0: + case TCPOLEN_COOKIE_MIN+2: + case TCPOLEN_COOKIE_MIN+4: + case TCPOLEN_COOKIE_MIN+6: + case TCPOLEN_COOKIE_MAX: + /* 16-bit multiple */ + opt_rx->cookie_plus = opsize; + *hvpp = ptr; + default: + /* ignore option */ + break; + }; + break; + }; ptr += opsize-2; length -= opsize; @@ -3813,17 +3836,20 @@ static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th) * If it is wrong it falls back on tcp_parse_options(). */ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, - struct tcp_sock *tp) + struct tcp_sock *tp, u8 **hvpp) { - if (th->doff == sizeof(struct tcphdr) >> 2) { + /* In the spirit of fast parsing, compare doff directly to constant + * values. Because equality is used, short doff can be ignored here. + */ + if (th->doff == (sizeof(*th) / 4)) { tp->rx_opt.saw_tstamp = 0; return 0; } else if (tp->rx_opt.tstamp_ok && - th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) { + th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4)) { if (tcp_parse_aligned_timestamp(tp, th)) return 1; } - tcp_parse_options(skb, &tp->rx_opt, 1, NULL); + tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL); return 1; } @@ -5077,10 +5103,12 @@ out: static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, struct tcphdr *th, int syn_inerr) { + u8 *hash_location; struct tcp_sock *tp = tcp_sk(sk); /* RFC1323: H1. Apply PAWS check first. */ - if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp && + if (tcp_fast_parse_options(skb, th, tp, &hash_location) && + tp->rx_opt.saw_tstamp && tcp_paws_discard(sk, skb)) { if (!th->rst) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); @@ -5368,12 +5396,14 @@ discard: static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, struct tcphdr *th, unsigned len) { - struct tcp_sock *tp = tcp_sk(sk); + u8 *hash_location; struct inet_connection_sock *icsk = inet_csk(sk); - int saved_clamp = tp->rx_opt.mss_clamp; + struct tcp_sock *tp = tcp_sk(sk); struct dst_entry *dst = __sk_dst_get(sk); + struct tcp_cookie_values *cvp = tp->cookie_values; + int saved_clamp = tp->rx_opt.mss_clamp; - tcp_parse_options(skb, &tp->rx_opt, 0, dst); + tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, dst); if (th->ack) { /* rfc793: @@ -5470,6 +5500,31 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, * Change state from SYN-SENT only after copied_seq * is initialized. */ tp->copied_seq = tp->rcv_nxt; + + if (cvp != NULL && + cvp->cookie_pair_size > 0 && + tp->rx_opt.cookie_plus > 0) { + int cookie_size = tp->rx_opt.cookie_plus + - TCPOLEN_COOKIE_BASE; + int cookie_pair_size = cookie_size + + cvp->cookie_desired; + + /* A cookie extension option was sent and returned. + * Note that each incoming SYNACK replaces the + * Responder cookie. The initial exchange is most + * fragile, as protection against spoofing relies + * entirely upon the sequence and timestamp (above). + * This replacement strategy allows the correct pair to + * pass through, while any others will be filtered via + * Responder verification later. + */ + if (sizeof(cvp->cookie_pair) >= cookie_pair_size) { + memcpy(&cvp->cookie_pair[cvp->cookie_desired], + hash_location, cookie_size); + cvp->cookie_pair_size = cookie_pair_size; + } + } + smp_mb(); tcp_set_state(sk, TCP_ESTABLISHED); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a2bcac9b388..59c911f3889 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1213,9 +1213,12 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = { int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) { + struct tcp_extend_values tmp_ext; struct tcp_options_received tmp_opt; + u8 *hash_location; struct request_sock *req; struct inet_request_sock *ireq; + struct tcp_sock *tp = tcp_sk(sk); struct dst_entry *dst = NULL; __be32 saddr = ip_hdr(skb)->saddr; __be32 daddr = ip_hdr(skb)->daddr; @@ -1271,15 +1274,49 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = TCP_MSS_DEFAULT; - tmp_opt.user_mss = tcp_sk(sk)->rx_opt.user_mss; + tmp_opt.user_mss = tp->rx_opt.user_mss; + tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst); + + if (tmp_opt.cookie_plus > 0 && + tmp_opt.saw_tstamp && + !tp->rx_opt.cookie_out_never && + (sysctl_tcp_cookie_size > 0 || + (tp->cookie_values != NULL && + tp->cookie_values->cookie_desired > 0))) { + u8 *c; + u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS]; + int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE; + + if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0) + goto drop_and_release; + + /* Secret recipe starts with IP addresses */ + *mess++ ^= daddr; + *mess++ ^= saddr; - tcp_parse_options(skb, &tmp_opt, 0, dst); + /* plus variable length Initiator Cookie */ + c = (u8 *)mess; + while (l-- > 0) + *c++ ^= *hash_location++; + +#ifdef CONFIG_SYN_COOKIES + want_cookie = 0; /* not our kind of cookie */ +#endif + tmp_ext.cookie_out_never = 0; /* false */ + tmp_ext.cookie_plus = tmp_opt.cookie_plus; + } else if (!tp->rx_opt.cookie_in_always) { + /* redundant indications, but ensure initialization. */ + tmp_ext.cookie_out_never = 1; /* true */ + tmp_ext.cookie_plus = 0; + } else { + goto drop_and_release; + } + tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always; if (want_cookie && !tmp_opt.saw_tstamp) tcp_clear_options(&tmp_opt); tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; - tcp_openreq_init(req, &tmp_opt, skb); if (security_inet_conn_request(sk, skb, req)) @@ -1339,7 +1376,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) } tcp_rsk(req)->snt_isn = isn; - if (__tcp_v4_send_synack(sk, dst, req, NULL) || want_cookie) + if (__tcp_v4_send_synack(sk, dst, req, + (struct request_values *)&tmp_ext) || + want_cookie) goto drop_and_free; inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 96852af43ca..87accec8d09 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -90,13 +90,14 @@ enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, const struct tcphdr *th) { - struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); struct tcp_options_received tmp_opt; + u8 *hash_location; + struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); int paws_reject = 0; if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { tmp_opt.tstamp_ok = 1; - tcp_parse_options(skb, &tmp_opt, 1, NULL); + tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL); if (tmp_opt.saw_tstamp) { tmp_opt.ts_recent = tcptw->tw_ts_recent; @@ -518,15 +519,16 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, struct request_sock *req, struct request_sock **prev) { + struct tcp_options_received tmp_opt; + u8 *hash_location; + struct sock *child; const struct tcphdr *th = tcp_hdr(skb); __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); int paws_reject = 0; - struct tcp_options_received tmp_opt; - struct sock *child; - if ((th->doff > (sizeof(struct tcphdr)>>2)) && (req->ts_recent)) { + if ((th->doff > (sizeof(*th) >> 2)) && (req->ts_recent)) { tmp_opt.tstamp_ok = 1; - tcp_parse_options(skb, &tmp_opt, 1, NULL); + tcp_parse_options(skb, &tmp_opt, &hash_location, 1, NULL); if (tmp_opt.saw_tstamp) { tmp_opt.ts_recent = req->ts_recent; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 35dd983a8a9..2ac8beff4d7 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -655,48 +655,77 @@ static unsigned tcp_synack_options(struct sock *sk, struct request_sock *req, unsigned mss, struct sk_buff *skb, struct tcp_out_options *opts, - struct tcp_md5sig_key **md5) { - unsigned size = 0; + struct tcp_md5sig_key **md5, + struct tcp_extend_values *xvp) +{ struct inet_request_sock *ireq = inet_rsk(req); - char doing_ts; + unsigned remaining = MAX_TCP_OPTION_SPACE; + u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ? + xvp->cookie_plus : + 0; + bool doing_ts = ireq->tstamp_ok; #ifdef CONFIG_TCP_MD5SIG *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); if (*md5) { opts->options |= OPTION_MD5; - size += TCPOLEN_MD5SIG_ALIGNED; + remaining -= TCPOLEN_MD5SIG_ALIGNED; + + /* We can't fit any SACK blocks in a packet with MD5 + TS + * options. There was discussion about disabling SACK + * rather than TS in order to fit in better with old, + * buggy kernels, but that was deemed to be unnecessary. + */ + doing_ts &= !ireq->sack_ok; } #else *md5 = NULL; #endif - /* we can't fit any SACK blocks in a packet with MD5 + TS - options. There was discussion about disabling SACK rather than TS in - order to fit in better with old, buggy kernels, but that was deemed - to be unnecessary. */ - doing_ts = ireq->tstamp_ok && !(*md5 && ireq->sack_ok); - + /* We always send an MSS option. */ opts->mss = mss; - size += TCPOLEN_MSS_ALIGNED; + remaining -= TCPOLEN_MSS_ALIGNED; if (likely(ireq->wscale_ok)) { opts->ws = ireq->rcv_wscale; opts->options |= OPTION_WSCALE; - size += TCPOLEN_WSCALE_ALIGNED; + remaining -= TCPOLEN_WSCALE_ALIGNED; } if (likely(doing_ts)) { opts->options |= OPTION_TS; opts->tsval = TCP_SKB_CB(skb)->when; opts->tsecr = req->ts_recent; - size += TCPOLEN_TSTAMP_ALIGNED; + remaining -= TCPOLEN_TSTAMP_ALIGNED; } if (likely(ireq->sack_ok)) { opts->options |= OPTION_SACK_ADVERTISE; if (unlikely(!doing_ts)) - size += TCPOLEN_SACKPERM_ALIGNED; + remaining -= TCPOLEN_SACKPERM_ALIGNED; } - return size; + /* Similar rationale to tcp_syn_options() applies here, too. + * If the options fit, the same options should fit now! + */ + if (*md5 == NULL && + doing_ts && + cookie_plus > TCPOLEN_COOKIE_BASE) { + int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */ + + if (0x2 & need) { + /* 32-bit multiple */ + need += 2; /* NOPs */ + } + if (need <= remaining) { + opts->options |= OPTION_COOKIE_EXTENSION; + opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE; + remaining -= need; + } else { + /* There's no error return, so flag it. */ + xvp->cookie_out_never = 1; /* true */ + opts->hash_size = 0; + } + } + return MAX_TCP_OPTION_SPACE - remaining; } /* Compute TCP options for ESTABLISHED sockets. This is not the @@ -2365,6 +2394,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, struct request_values *rvp) { struct tcp_out_options opts; + struct tcp_extend_values *xvp = tcp_xv(rvp); struct inet_request_sock *ireq = inet_rsk(req); struct tcp_sock *tp = tcp_sk(sk); struct tcphdr *th; @@ -2408,8 +2438,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, #endif TCP_SKB_CB(skb)->when = tcp_time_stamp; tcp_header_size = tcp_synack_options(sk, req, mss, - skb, &opts, &md5) + - sizeof(struct tcphdr); + skb, &opts, &md5, xvp) + + sizeof(*th); skb_push(skb, tcp_header_size); skb_reset_transport_header(skb); @@ -2426,6 +2456,45 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, */ tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, TCPCB_FLAG_SYN | TCPCB_FLAG_ACK); + + if (OPTION_COOKIE_EXTENSION & opts.options) { + const struct tcp_cookie_values *cvp = tp->cookie_values; + + if (cvp != NULL && + cvp->s_data_constant && + cvp->s_data_desired > 0) { + u8 *buf = skb_put(skb, cvp->s_data_desired); + + /* copy data directly from the listening socket. */ + memcpy(buf, cvp->s_data_payload, cvp->s_data_desired); + TCP_SKB_CB(skb)->end_seq += cvp->s_data_desired; + } + + if (opts.hash_size > 0) { + __u32 workspace[SHA_WORKSPACE_WORDS]; + u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS]; + u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1]; + + /* Secret recipe depends on the Timestamp, (future) + * Sequence and Acknowledgment Numbers, Initiator + * Cookie, and others handled by IP variant caller. + */ + *tail-- ^= opts.tsval; + *tail-- ^= tcp_rsk(req)->rcv_isn + 1; + *tail-- ^= TCP_SKB_CB(skb)->seq + 1; + + /* recommended */ + *tail-- ^= ((th->dest << 16) | th->source); + *tail-- ^= (u32)cvp; /* per sockopt */ + + sha_transform((__u32 *)&xvp->cookie_bakery[0], + (char *)mess, + &workspace[0]); + opts.hash_location = + (__u8 *)&xvp->cookie_bakery[0]; + } + } + th->seq = htonl(TCP_SKB_CB(skb)->seq); th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 612fc53e0bb..5b9af508b8f 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -159,6 +159,8 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie) struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) { + struct tcp_options_received tcp_opt; + u8 *hash_location; struct inet_request_sock *ireq; struct inet6_request_sock *ireq6; struct tcp_request_sock *treq; @@ -171,7 +173,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) int mss; struct dst_entry *dst; __u8 rcv_wscale; - struct tcp_options_received tcp_opt; if (!sysctl_tcp_syncookies || !th->ack) goto out; @@ -254,7 +255,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) /* check for timestamp cookie support */ memset(&tcp_opt, 0, sizeof(tcp_opt)); - tcp_parse_options(skb, &tcp_opt, 0, dst); + tcp_parse_options(skb, &tcp_opt, &hash_location, 0, dst); if (tcp_opt.saw_tstamp) cookie_check_timestamp(&tcp_opt); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f2ec38289a4..fc0a4e5895e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1162,7 +1162,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) */ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) { + struct tcp_extend_values tmp_ext; struct tcp_options_received tmp_opt; + u8 *hash_location; struct request_sock *req; struct inet6_request_sock *treq; struct ipv6_pinfo *np = inet6_sk(sk); @@ -1206,8 +1208,52 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); tmp_opt.user_mss = tp->rx_opt.user_mss; + tcp_parse_options(skb, &tmp_opt, &hash_location, 0, dst); + + if (tmp_opt.cookie_plus > 0 && + tmp_opt.saw_tstamp && + !tp->rx_opt.cookie_out_never && + (sysctl_tcp_cookie_size > 0 || + (tp->cookie_values != NULL && + tp->cookie_values->cookie_desired > 0))) { + u8 *c; + u32 *d; + u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS]; + int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE; + + if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0) + goto drop_and_free; + + /* Secret recipe starts with IP addresses */ + d = &ipv6_hdr(skb)->daddr.s6_addr32[0]; + *mess++ ^= *d++; + *mess++ ^= *d++; + *mess++ ^= *d++; + *mess++ ^= *d++; + d = &ipv6_hdr(skb)->saddr.s6_addr32[0]; + *mess++ ^= *d++; + *mess++ ^= *d++; + *mess++ ^= *d++; + *mess++ ^= *d++; + + /* plus variable length Initiator Cookie */ + c = (u8 *)mess; + while (l-- > 0) + *c++ ^= *hash_location++; - tcp_parse_options(skb, &tmp_opt, 0, dst); +#ifdef CONFIG_SYN_COOKIES + want_cookie = 0; /* not our kind of cookie */ +#endif + tmp_ext.cookie_out_never = 0; /* false */ + tmp_ext.cookie_plus = tmp_opt.cookie_plus; + } else if (!tp->rx_opt.cookie_in_always) { + /* redundant indications, but ensure initialization. */ + tmp_ext.cookie_out_never = 1; /* true */ + tmp_ext.cookie_plus = 0; + } else { + goto drop_and_free; + } + tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always; if (want_cookie && !tmp_opt.saw_tstamp) tcp_clear_options(&tmp_opt); @@ -1244,7 +1290,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) security_inet_conn_request(sk, skb, req); - if (tcp_v6_send_synack(sk, req, NULL) || want_cookie) + if (tcp_v6_send_synack(sk, req, + (struct request_values *)&tmp_ext) || + want_cookie) goto drop_and_free; inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); -- cgit v1.2.3 From 91e2ff3528ac90b9dbcb04b76488e8ad74e3d3d9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 2 Dec 2009 13:19:08 +0000 Subject: net: Teach vlans to cleanup as a pernet subsystem Take advantage of the fact that an explicit rtnl_kill_links is unnecessary (and skipping it improves batching), as network namespace exit calls dellink on all remaining virtual devices, and rtnl_link_unregister calls dellink on all outstanding devices in that network namespace. To do this we need to leave the vlan proc directories in place until after network device exit time, which is done by using register_pernet_subsys instead of register_pernet_device. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/8021q/vlan.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 91e9073e199..ec3769295da 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -698,8 +698,6 @@ static int vlan_init_net(struct net *net) static void vlan_exit_net(struct net *net) { - rtnl_kill_links(net, &vlan_link_ops); - vlan_proc_cleanup(net); } @@ -717,7 +715,7 @@ static int __init vlan_proto_init(void) pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); pr_info("All bugs added by %s\n", vlan_buggyright); - err = register_pernet_device(&vlan_net_ops); + err = register_pernet_subsys(&vlan_net_ops); if (err < 0) goto err0; @@ -742,7 +740,7 @@ err4: err3: unregister_netdevice_notifier(&vlan_notifier_block); err2: - unregister_pernet_device(&vlan_net_ops); + unregister_pernet_subsys(&vlan_net_ops); err0: return err; } @@ -762,7 +760,7 @@ static void __exit vlan_cleanup_module(void) for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) BUG_ON(!hlist_empty(&vlan_group_hash[i])); - unregister_pernet_device(&vlan_net_ops); + unregister_pernet_subsys(&vlan_net_ops); rcu_barrier(); /* Wait for completion of call_rcu()'s */ vlan_gvrp_uninit(); -- cgit v1.2.3 From f9a2e69e8bb77fe6c8e7da6380ebd4330c00a29e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 2 Dec 2009 22:12:04 -0800 Subject: tcp: Fix warning on 64-bit. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/ipv4/tcp_output.c: In function ‘tcp_make_synack’: net/ipv4/tcp_output.c:2488: warning: cast from pointer to integer of different size Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2ac8beff4d7..c08e06d4442 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2485,7 +2485,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, /* recommended */ *tail-- ^= ((th->dest << 16) | th->source); - *tail-- ^= (u32)cvp; /* per sockopt */ + *tail-- ^= (u32)(unsigned long)cvp; /* per sockopt */ sha_transform((__u32 *)&xvp->cookie_bakery[0], (char *)mess, -- cgit v1.2.3 From e6b09ccada2e4ab8ee25a7c3ac72fcd1bc7101c4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 2 Dec 2009 22:18:58 -0800 Subject: tcp: sysctl_tcp_cookie_size needs to be exported to modules. Otherwise: ERROR: "sysctl_tcp_cookie_size" [net/ipv6/ipv6.ko] undefined! make[1]: *** [__modpost] Error 1 Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c08e06d4442..93316a96d82 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -60,6 +60,7 @@ int sysctl_tcp_base_mss __read_mostly = 512; int sysctl_tcp_slow_start_after_idle __read_mostly = 1; int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */ +EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size); /* Account for new data that has been sent to the network. */ -- cgit v1.2.3 From 2da31939a42f7a676a0bc5155d6a0a39ed8451f2 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 26 Nov 2009 16:20:56 +0100 Subject: Bluetooth: Implement raw output support for HIDP layer Implement raw output callback which is used by hidraw to send raw data to the underlying device. Without this patch, the userspace hidraw-based applications can't send output reports to HID Bluetooth devices. Reported-and-tested-by: Brian Gunn Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann --- net/bluetooth/hidp/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 49d8495d69b..569750010fd 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -280,6 +280,13 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep return hidp_queue_report(session, buf, rsize); } +static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count) +{ + if (hidp_queue_report(hid->driver_data, data, count)) + return -ENOMEM; + return count; +} + static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; @@ -785,6 +792,8 @@ static int hidp_setup_hid(struct hidp_session *session, hid->dev.parent = hidp_get_device(session); hid->ll_driver = &hidp_hid_driver; + hid->hid_output_raw_report = hidp_output_raw_report; + err = hid_add_device(hid); if (err < 0) goto failed; -- cgit v1.2.3 From 7e21addcd0ad87696c17409399e56e874931da57 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 18 Nov 2009 01:05:00 +0100 Subject: Bluetooth: Return ENETDOWN when interface is down Sending commands to a down interface results in a timeout while clearly it should just return ENETDOWN. When using the ioctls this works fine, but not when using the HCI sockets sendmsg interface. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sock.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1ca5c7ca9bd..c3701f37aeb 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -414,6 +414,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, goto done; } + if (!test_bit(HCI_UP, &hdev->flags)) { + err = -ENETDOWN; + goto done; + } + if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) goto done; -- cgit v1.2.3 From 76bca88012e1d27de794f32cc551d6314d38b6d9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 18 Nov 2009 00:40:39 +0100 Subject: Bluetooth: Turn hci_recv_frame into an exported function For future simplification it is important that the hci_recv_frame function is no longer an inline function. So move it into the module itself and export it. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 23 +---------------------- net/bluetooth/hci_core.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7b640aeddb6..8460f228308 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -437,28 +437,7 @@ int hci_inquiry(void __user *arg); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); -/* Receive frame from HCI drivers */ -static inline int hci_recv_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - if (!hdev || (!test_bit(HCI_UP, &hdev->flags) - && !test_bit(HCI_INIT, &hdev->flags))) { - kfree_skb(skb); - return -ENXIO; - } - - /* Incomming skb */ - bt_cb(skb)->incoming = 1; - - /* Time stamp */ - __net_timestamp(skb); - - /* Queue frame for rx task */ - skb_queue_tail(&hdev->rx_q, skb); - hci_sched_rx(hdev); - return 0; -} - +int hci_recv_frame(struct sk_buff *skb); int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count); int hci_register_sysfs(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e1da8f68759..3fc90e543ec 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -987,6 +987,29 @@ int hci_resume_dev(struct hci_dev *hdev) } EXPORT_SYMBOL(hci_resume_dev); +/* Receive frame from HCI drivers */ +int hci_recv_frame(struct sk_buff *skb) +{ + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + if (!hdev || (!test_bit(HCI_UP, &hdev->flags) + && !test_bit(HCI_INIT, &hdev->flags))) { + kfree_skb(skb); + return -ENXIO; + } + + /* Incomming skb */ + bt_cb(skb)->incoming = 1; + + /* Time stamp */ + __net_timestamp(skb); + + /* Queue frame for rx task */ + skb_queue_tail(&hdev->rx_q, skb); + hci_sched_rx(hdev); + return 0; +} +EXPORT_SYMBOL(hci_recv_frame); + /* Receive packet type fragment */ #define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 2]) -- cgit v1.2.3 From c78ae283145d3a8799b2fb01650166a66af3bff8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 18 Nov 2009 01:02:54 +0100 Subject: Bluetooth: Unobfuscate tasklet_schedule usage The tasklet schedule function helpers are just an obfuscation. So remove them and call the schedule functions directly. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 16 ---------------- net/bluetooth/hci_core.c | 18 ++++++++++++------ net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/hci_sock.c | 6 +++--- 4 files changed, 18 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8460f228308..7b86094a894 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -367,22 +367,6 @@ static inline void hci_conn_put(struct hci_conn *conn) } } -/* ----- HCI tasks ----- */ -static inline void hci_sched_cmd(struct hci_dev *hdev) -{ - tasklet_schedule(&hdev->cmd_task); -} - -static inline void hci_sched_rx(struct hci_dev *hdev) -{ - tasklet_schedule(&hdev->rx_task); -} - -static inline void hci_sched_tx(struct hci_dev *hdev) -{ - tasklet_schedule(&hdev->tx_task); -} - /* ----- HCI Devices ----- */ static inline void __hci_dev_put(struct hci_dev *d) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3fc90e543ec..94ba3498202 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -193,8 +193,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) while ((skb = skb_dequeue(&hdev->driver_init))) { bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; skb->dev = (void *) hdev; + skb_queue_tail(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } skb_queue_purge(&hdev->driver_init); @@ -1005,7 +1006,8 @@ int hci_recv_frame(struct sk_buff *skb) /* Queue frame for rx task */ skb_queue_tail(&hdev->rx_q, skb); - hci_sched_rx(hdev); + tasklet_schedule(&hdev->rx_task); + return 0; } EXPORT_SYMBOL(hci_recv_frame); @@ -1216,8 +1218,9 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; skb->dev = (void *) hdev; + skb_queue_tail(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); return 0; } @@ -1294,7 +1297,8 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) spin_unlock_bh(&conn->data_q.lock); } - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); + return 0; } EXPORT_SYMBOL(hci_send_acl); @@ -1321,8 +1325,10 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) skb->dev = (void *) hdev; bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; + skb_queue_tail(&conn->data_q, skb); - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); + return 0; } EXPORT_SYMBOL(hci_send_sco); @@ -1635,7 +1641,7 @@ static void hci_cmd_task(unsigned long arg) hdev->cmd_last_tx = jiffies; } else { skb_queue_head(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e99fe385fba..28517bad796 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1320,7 +1320,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } @@ -1386,7 +1386,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } @@ -1454,7 +1454,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s } } - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); tasklet_enable(&hdev->tx_task); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c3701f37aeb..688cfebfbee 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -445,10 +445,10 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { skb_queue_tail(&hdev->raw_q, skb); - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); } else { skb_queue_tail(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } else { if (!capable(CAP_NET_RAW)) { @@ -457,7 +457,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } skb_queue_tail(&hdev->raw_q, skb); - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); } err = len; -- cgit v1.2.3 From cde9f807f003676862178a6f28b52c7d431511ed Mon Sep 17 00:00:00 2001 From: Vikram Kandukuri Date: Thu, 3 Dec 2009 15:12:51 +0530 Subject: Bluetooth: Fix handling of BNEP setup connection requests According to BNEP test specification the proper response should be sent for a setup connection request message after the BNEP connection setup has been completed. Signed-off-by: Vikram Kandukuri Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index cafe9f54d84..29b1b220d6c 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -230,7 +230,6 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) switch (cmd) { case BNEP_CMD_NOT_UNDERSTOOD: - case BNEP_SETUP_CONN_REQ: case BNEP_SETUP_CONN_RSP: case BNEP_FILTER_NET_TYPE_RSP: case BNEP_FILTER_MULTI_ADDR_RSP: @@ -245,6 +244,10 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) err = bnep_ctrl_set_mcfilter(s, data, len); break; + case BNEP_SETUP_CONN_REQ: + err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED); + break; + default: { u8 pkt[3]; pkt[0] = BNEP_CONTROL; -- cgit v1.2.3 From 0565c1c24af94130b891f989fa608faddfadc52c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:36 -0300 Subject: Bluetooth: Initialize variables and timers for both channel's sides Fix ERTM's full-duplex channel to work as specified by ERTM spec. ERTM needs to handle state vars, timers and counters to send and receive I-frames(the data frames), i.e., for both sides of data communication. We initialize all of them to the default values here. Full-duplex channel is a mandatory feature of ERTM spec. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 54 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 54992f78230..dfd0327cf8d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2173,6 +2173,21 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) *ptr += L2CAP_CONF_OPT_SIZE + len; } +static inline void l2cap_ertm_init(struct sock *sk) +{ + l2cap_pi(sk)->expected_ack_seq = 0; + l2cap_pi(sk)->unacked_frames = 0; + l2cap_pi(sk)->buffer_seq = 0; + l2cap_pi(sk)->num_to_ack = 0; + + setup_timer(&l2cap_pi(sk)->retrans_timer, + l2cap_retrans_timeout, (unsigned long) sk); + setup_timer(&l2cap_pi(sk)->monitor_timer, + l2cap_monitor_timeout, (unsigned long) sk); + + __skb_queue_head_init(SREJ_QUEUE(sk)); +} + static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) { u32 local_feat_mask = l2cap_feat_mask; @@ -2761,17 +2776,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; sk->sk_state = BT_CONNECTED; - l2cap_pi(sk)->next_tx_seq = 0; - l2cap_pi(sk)->expected_ack_seq = 0; - l2cap_pi(sk)->unacked_frames = 0; - - setup_timer(&l2cap_pi(sk)->retrans_timer, - l2cap_retrans_timeout, (unsigned long) sk); - setup_timer(&l2cap_pi(sk)->monitor_timer, - l2cap_monitor_timeout, (unsigned long) sk); + l2cap_pi(sk)->next_tx_seq = 0; + l2cap_pi(sk)->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); - __skb_queue_head_init(SREJ_QUEUE(sk)); + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + l2cap_ertm_init(sk); + l2cap_chan_ready(sk); goto unlock; } @@ -2850,11 +2861,12 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; sk->sk_state = BT_CONNECTED; + l2cap_pi(sk)->next_tx_seq = 0; l2cap_pi(sk)->expected_tx_seq = 0; - l2cap_pi(sk)->buffer_seq = 0; - l2cap_pi(sk)->num_to_ack = 0; __skb_queue_head_init(TX_QUEUE(sk)); - __skb_queue_head_init(SREJ_QUEUE(sk)); + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + l2cap_ertm_init(sk); + l2cap_chan_ready(sk); } @@ -2886,9 +2898,12 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; skb_queue_purge(TX_QUEUE(sk)); - skb_queue_purge(SREJ_QUEUE(sk)); - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + skb_queue_purge(SREJ_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + } l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); @@ -2913,9 +2928,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; skb_queue_purge(TX_QUEUE(sk)); - skb_queue_purge(SREJ_QUEUE(sk)); - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + skb_queue_purge(SREJ_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + } l2cap_chan_del(sk, 0); bh_unlock_sock(sk); -- cgit v1.2.3 From 889a3ca466018ab68363c3168993793bc2d984f1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:37 -0300 Subject: Bluetooth: Fix unset of SrejActioned flag SrejActioned is a flag that when set prevents local side to retransmit a I-frame(the data frame) already retransmitted. The local entity can retransmit again only when it receives a SREJ frame with the F-bit set. SREJ frame - Selective Reject frame - is sent when an entity wants the retransmission of a specific I-frame that was lost or corrupted. This bug can put ERTM in an unknown state once the entity can't retransmit. A frame with the Final bit set is expected when the local side sends a frame with the Poll bit set due to a local busy condition or a retransmission timer expired. (Receipt of P-bit shall always be replied by a frame with the F-bit set). pi->conn_state keeps informations about many ERTM flags including SrejActioned. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index dfd0327cf8d..2d5d37545b1 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3443,7 +3443,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str } else if (rx_control & L2CAP_CTRL_FINAL) { if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && pi->srej_save_reqseq == tx_seq) - pi->srej_save_reqseq &= ~L2CAP_CONN_SREJ_ACT; + pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; else l2cap_retransmit_frame(sk, tx_seq); } -- cgit v1.2.3 From 9f121a5a80b4417c6db5a35e26d2e79c29c3fc0d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:38 -0300 Subject: Bluetooth: Fix sending ReqSeq on I-frames As specified by ERTM spec an ERTM channel can acknowledge received I-frames(the data frames) by sending an I-frame with the proper ReqSeq value (i.e. ReqSeq is set to BufferSeq). Until now we aren't setting the ReqSeq value on I-frame control bits. That way we can save sending S-frames(Supervise frames) only to acknowledge receipt of I-frames. It is very helpful to the full-duplex channel. ReqSeq is the packet sequence number sent in an acknowledgement frame to acknowledge receipt of frames up to (ReqSeq - 1). BufferSeq controls the receiver buffer, it is used to delay acknowledgement of new frames to not cause buffer overflow. BufferSeq value is not increased until frames are pulled by reassembly function. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap.c | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9516f4b4a3c..327eb57dab5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -324,7 +324,6 @@ struct l2cap_pinfo { __u8 next_tx_seq; __u8 expected_ack_seq; - __u8 req_seq; __u8 expected_tx_seq; __u8 buffer_seq; __u8 buffer_seq_srej; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2d5d37545b1..78ab8811e5e 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1333,7 +1333,7 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) tx_skb = skb_clone(skb, GFP_ATOMIC); bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); - control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) + control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1375,7 +1375,7 @@ static int l2cap_ertm_send(struct sock *sk) bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); - control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) + control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -3298,12 +3298,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str { struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_txseq(rx_control); + u8 req_seq = __get_reqseq(rx_control); u16 tx_control = 0; u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; int err = 0; BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + pi->expected_ack_seq = req_seq; + l2cap_drop_acked_frames(sk); + if (tx_seq == pi->expected_tx_seq) goto expected; -- cgit v1.2.3 From 4ec10d9720ef78cd81d8bcc30a3238665744569f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:39 -0300 Subject: Bluetooth: Implement RejActioned flag RejActioned is used to prevent retransmission when a entity is on the WAIT_F state, i.e., waiting for a frame with F-bit set due local busy condition or a expired retransmission timer. (When these two events raise they send a frame with the Poll bit set and enters in the WAIT_F state to wait for a frame with the Final bit set.) The local entity doesn't send I-frames(the data frames) until the receipt of a frame with F-bit set. When that happens it also set RejActioned to false. RejActioned is a mandatory feature of ERTM spec. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 327eb57dab5..17a689f27a6 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -374,6 +374,7 @@ struct l2cap_pinfo { #define L2CAP_CONN_SEND_PBIT 0x10 #define L2CAP_CONN_REMOTE_BUSY 0x20 #define L2CAP_CONN_LOCAL_BUSY 0x40 +#define L2CAP_CONN_REJ_ACT 0x80 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 78ab8811e5e..73bda0ae41d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3362,6 +3362,16 @@ expected: return 0; } + if (rx_control & L2CAP_CTRL_FINAL) { + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); + } + } + pi->buffer_seq = (pi->buffer_seq + 1) % 64; err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); @@ -3398,6 +3408,14 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); + } + if (!(pi->conn_state & L2CAP_CONN_WAIT_F)) break; @@ -3425,10 +3443,24 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str pi->expected_ack_seq = __get_reqseq(rx_control); l2cap_drop_acked_frames(sk); - sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; + if (rx_control & L2CAP_CTRL_FINAL) { + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); + } + } else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); - l2cap_ertm_send(sk); + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_REJ_ACT; + } + } break; -- cgit v1.2.3 From 2ab25cdd7b54473dd42dcffc9872737de2517466 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:40 -0300 Subject: Bluetooth: Fix 'SendRRorRNR' to send the ReqSeq value SendRRorRNR needs to acknowledge received I-frames (actually every packet needs to acknowledge received I-frames by sending the proper packet sequence number), so ReqSeq is set to the next I-frame number sequence to be pulled by the reassembly function. SendRRorRNR tells the remote side about local busy conditions, it sends a Receiver Ready frame if local busy is false or a Receiver Not Ready if local busy is true. ReqSeq is the packet's field to send the number of the acknowledged packets. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 73bda0ae41d..c898f3439d1 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -373,6 +373,8 @@ static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) else control |= L2CAP_SUPER_RCV_READY; + control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + return l2cap_send_sframe(pi, control); } -- cgit v1.2.3 From 5fbcd3d1a07e234583e17830e8aef47282c22141 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 5 Oct 2009 11:35:43 +0200 Subject: Bluetooth: Add L2CAP option for max transmit value For testing purposes it is important to modify the max transmit value. Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c898f3439d1..5129b88c8e5 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -54,6 +54,7 @@ #define VERSION "2.14" static int enable_ertm = 0; +static int max_transmit = L2CAP_DEFAULT_MAX_TX; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; @@ -2253,7 +2254,7 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; - rfc.max_transmit = L2CAP_DEFAULT_MAX_TX; + rfc.max_transmit = max_transmit; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); @@ -4060,6 +4061,9 @@ module_exit(l2cap_exit); module_param(enable_ertm, bool, 0644); MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode"); +module_param(max_transmit, uint, 0644); +MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)"); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_VERSION(VERSION); -- cgit v1.2.3 From eae38eede2e5f70d65f09327297bd698b0d3ea7e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 5 Oct 2009 12:23:48 +0200 Subject: Bluetooth: Add RFCOMM option to use L2CAP ERTM mode By default the RFCOMM layer would still use L2CAP basic mode. For testing purposes this option enables RFCOMM to select enhanced retransmission mode. Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 25692bc0a34..fc5ee3296e2 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -51,6 +51,7 @@ static int disable_cfc = 0; static int channel_mtu = -1; static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU; +static int l2cap_ertm = 0; static struct task_struct *rfcomm_thread; @@ -702,6 +703,8 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst sk = sock->sk; lock_sock(sk); l2cap_pi(sk)->imtu = l2cap_mtu; + if (l2cap_ertm) + l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; release_sock(sk); s = rfcomm_session_add(sock, BT_BOUND); @@ -2185,6 +2188,9 @@ MODULE_PARM_DESC(channel_mtu, "Default MTU for the RFCOMM channel"); module_param(l2cap_mtu, uint, 0644); MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection"); +module_param(l2cap_ertm, bool, 0644); +MODULE_PARM_DESC(l2cap_ertm, "Use L2CAP ERTM mode for connection"); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION); MODULE_VERSION(VERSION); -- cgit v1.2.3 From 491deb24bf5bf7124141287aaf02c3219783ceab Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 3 Dec 2009 01:25:54 +0000 Subject: net 02/05: fib_rules: rename ifindex/ifname/FRA_IFNAME to iifindex/iifname/FRA_IIFNAME commit 229e77eec406ad68662f18e49fda8b5d366768c5 Author: Patrick McHardy Date: Thu Dec 3 12:05:23 2009 +0100 net: fib_rules: rename ifindex/ifname/FRA_IFNAME to iifindex/iifname/FRA_IIFNAME The next patch will add oif classification, rename interface related members and attributes to reflect that they're used for iif classification. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/fib_rules.h | 6 ++++-- include/net/fib_rules.h | 6 +++--- net/core/fib_rules.c | 36 ++++++++++++++++++------------------ 3 files changed, 25 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index c7e5b700bb9..7e11bb2fa65 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -8,7 +8,8 @@ #define FIB_RULE_PERMANENT 0x00000001 #define FIB_RULE_INVERT 0x00000002 #define FIB_RULE_UNRESOLVED 0x00000004 -#define FIB_RULE_DEV_DETACHED 0x00000008 +#define FIB_RULE_IIF_DETACHED 0x00000008 +#define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED /* try to find source address in routing lookups */ #define FIB_RULE_FIND_SADDR 0x00010000 @@ -31,7 +32,8 @@ enum { FRA_UNSPEC, FRA_DST, /* destination address */ FRA_SRC, /* source address */ - FRA_IFNAME, /* interface name */ + FRA_IIFNAME, /* interface name */ +#define FRA_IFNAME FRA_IIFNAME FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */ FRA_UNUSED2, FRA_PRIORITY, /* priority/preference */ diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 22fb323cd85..62bebcb2a51 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -10,7 +10,7 @@ struct fib_rule { struct list_head list; atomic_t refcnt; - int ifindex; + int iifindex; u32 mark; u32 mark_mask; u32 pref; @@ -19,7 +19,7 @@ struct fib_rule { u8 action; u32 target; struct fib_rule * ctarget; - char ifname[IFNAMSIZ]; + char iifname[IFNAMSIZ]; struct rcu_head rcu; struct net * fr_net; }; @@ -67,7 +67,7 @@ struct fib_rules_ops { }; #define FRA_GENERIC_POLICY \ - [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ + [FRA_IIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ [FRA_PRIORITY] = { .type = NLA_U32 }, \ [FRA_FWMARK] = { .type = NLA_U32 }, \ [FRA_FWMASK] = { .type = NLA_U32 }, \ diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index bd309384f8b..8e8028cdc87 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -135,7 +135,7 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, { int ret = 0; - if (rule->ifindex && (rule->ifindex != fl->iif)) + if (rule->iifindex && (rule->iifindex != fl->iif)) goto out; if ((rule->mark ^ fl->mark) & rule->mark_mask) @@ -248,14 +248,14 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) if (tb[FRA_PRIORITY]) rule->pref = nla_get_u32(tb[FRA_PRIORITY]); - if (tb[FRA_IFNAME]) { + if (tb[FRA_IIFNAME]) { struct net_device *dev; - rule->ifindex = -1; - nla_strlcpy(rule->ifname, tb[FRA_IFNAME], IFNAMSIZ); - dev = __dev_get_by_name(net, rule->ifname); + rule->iifindex = -1; + nla_strlcpy(rule->iifname, tb[FRA_IIFNAME], IFNAMSIZ); + dev = __dev_get_by_name(net, rule->iifname); if (dev) - rule->ifindex = dev->ifindex; + rule->iifindex = dev->ifindex; } if (tb[FRA_FWMARK]) { @@ -388,8 +388,8 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) (rule->pref != nla_get_u32(tb[FRA_PRIORITY]))) continue; - if (tb[FRA_IFNAME] && - nla_strcmp(tb[FRA_IFNAME], rule->ifname)) + if (tb[FRA_IIFNAME] && + nla_strcmp(tb[FRA_IIFNAME], rule->iifname)) continue; if (tb[FRA_FWMARK] && @@ -447,7 +447,7 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, struct fib_rule *rule) { size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr)) - + nla_total_size(IFNAMSIZ) /* FRA_IFNAME */ + + nla_total_size(IFNAMSIZ) /* FRA_IIFNAME */ + nla_total_size(4) /* FRA_PRIORITY */ + nla_total_size(4) /* FRA_TABLE */ + nla_total_size(4) /* FRA_FWMARK */ @@ -481,11 +481,11 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, if (rule->action == FR_ACT_GOTO && rule->ctarget == NULL) frh->flags |= FIB_RULE_UNRESOLVED; - if (rule->ifname[0]) { - NLA_PUT_STRING(skb, FRA_IFNAME, rule->ifname); + if (rule->iifname[0]) { + NLA_PUT_STRING(skb, FRA_IIFNAME, rule->iifname); - if (rule->ifindex == -1) - frh->flags |= FIB_RULE_DEV_DETACHED; + if (rule->iifindex == -1) + frh->flags |= FIB_RULE_IIF_DETACHED; } if (rule->pref) @@ -600,9 +600,9 @@ static void attach_rules(struct list_head *rules, struct net_device *dev) struct fib_rule *rule; list_for_each_entry(rule, rules, list) { - if (rule->ifindex == -1 && - strcmp(dev->name, rule->ifname) == 0) - rule->ifindex = dev->ifindex; + if (rule->iifindex == -1 && + strcmp(dev->name, rule->iifname) == 0) + rule->iifindex = dev->ifindex; } } @@ -611,8 +611,8 @@ static void detach_rules(struct list_head *rules, struct net_device *dev) struct fib_rule *rule; list_for_each_entry(rule, rules, list) - if (rule->ifindex == dev->ifindex) - rule->ifindex = -1; + if (rule->iifindex == dev->ifindex) + rule->iifindex = -1; } -- cgit v1.2.3 From 1b038a5e60c7812f19818e8a5df96d029e49c38f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 3 Dec 2009 01:25:56 +0000 Subject: net 03/05: fib_rules: add oif classification commit 68144d350f4f6c348659c825cde6a82b34c27a91 Author: Patrick McHardy Date: Thu Dec 3 12:05:25 2009 +0100 net: fib_rules: add oif classification Support routing table lookup based on the flow's oif. This is useful to classify packets originating from sockets bound to interfaces differently. The route cache already includes the oif and needs no changes. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/fib_rules.h | 2 ++ include/net/fib_rules.h | 3 +++ net/core/fib_rules.c | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 7e11bb2fa65..51da65b68b8 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -10,6 +10,7 @@ #define FIB_RULE_UNRESOLVED 0x00000004 #define FIB_RULE_IIF_DETACHED 0x00000008 #define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED +#define FIB_RULE_OIF_DETACHED 0x00000010 /* try to find source address in routing lookups */ #define FIB_RULE_FIND_SADDR 0x00010000 @@ -47,6 +48,7 @@ enum { FRA_UNUSED8, FRA_TABLE, /* Extended table id */ FRA_FWMASK, /* mask for netfilter mark */ + FRA_OIFNAME, __FRA_MAX }; diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 62bebcb2a51..d4e875a58f8 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -11,6 +11,7 @@ struct fib_rule { struct list_head list; atomic_t refcnt; int iifindex; + int oifindex; u32 mark; u32 mark_mask; u32 pref; @@ -20,6 +21,7 @@ struct fib_rule { u32 target; struct fib_rule * ctarget; char iifname[IFNAMSIZ]; + char oifname[IFNAMSIZ]; struct rcu_head rcu; struct net * fr_net; }; @@ -68,6 +70,7 @@ struct fib_rules_ops { #define FRA_GENERIC_POLICY \ [FRA_IIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ + [FRA_OIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ [FRA_PRIORITY] = { .type = NLA_U32 }, \ [FRA_FWMARK] = { .type = NLA_U32 }, \ [FRA_FWMASK] = { .type = NLA_U32 }, \ diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 8e8028cdc87..d1a70ad4b54 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -138,6 +138,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, if (rule->iifindex && (rule->iifindex != fl->iif)) goto out; + if (rule->oifindex && (rule->oifindex != fl->oif)) + goto out; + if ((rule->mark ^ fl->mark) & rule->mark_mask) goto out; @@ -258,6 +261,16 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) rule->iifindex = dev->ifindex; } + if (tb[FRA_OIFNAME]) { + struct net_device *dev; + + rule->oifindex = -1; + nla_strlcpy(rule->oifname, tb[FRA_OIFNAME], IFNAMSIZ); + dev = __dev_get_by_name(net, rule->oifname); + if (dev) + rule->oifindex = dev->ifindex; + } + if (tb[FRA_FWMARK]) { rule->mark = nla_get_u32(tb[FRA_FWMARK]); if (rule->mark) @@ -392,6 +405,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) nla_strcmp(tb[FRA_IIFNAME], rule->iifname)) continue; + if (tb[FRA_OIFNAME] && + nla_strcmp(tb[FRA_OIFNAME], rule->oifname)) + continue; + if (tb[FRA_FWMARK] && (rule->mark != nla_get_u32(tb[FRA_FWMARK]))) continue; @@ -448,6 +465,7 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, { size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr)) + nla_total_size(IFNAMSIZ) /* FRA_IIFNAME */ + + nla_total_size(IFNAMSIZ) /* FRA_OIFNAME */ + nla_total_size(4) /* FRA_PRIORITY */ + nla_total_size(4) /* FRA_TABLE */ + nla_total_size(4) /* FRA_FWMARK */ @@ -488,6 +506,13 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, frh->flags |= FIB_RULE_IIF_DETACHED; } + if (rule->oifname[0]) { + NLA_PUT_STRING(skb, FRA_OIFNAME, rule->oifname); + + if (rule->oifindex == -1) + frh->flags |= FIB_RULE_OIF_DETACHED; + } + if (rule->pref) NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref); @@ -603,6 +628,9 @@ static void attach_rules(struct list_head *rules, struct net_device *dev) if (rule->iifindex == -1 && strcmp(dev->name, rule->iifname) == 0) rule->iifindex = dev->ifindex; + if (rule->oifindex == -1 && + strcmp(dev->name, rule->oifname) == 0) + rule->oifindex = dev->ifindex; } } @@ -610,9 +638,12 @@ static void detach_rules(struct list_head *rules, struct net_device *dev) { struct fib_rule *rule; - list_for_each_entry(rule, rules, list) + list_for_each_entry(rule, rules, list) { if (rule->iifindex == dev->ifindex) rule->iifindex = -1; + if (rule->oifindex == dev->ifindex) + rule->oifindex = -1; + } } -- cgit v1.2.3 From 5adef1809147a9c39119ffd5a13a1ca4fe23a411 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 3 Dec 2009 01:25:57 +0000 Subject: net 04/05: fib_rules: allow to delete local rule commit d124356ce314fff22a047ea334379d5105b2d834 Author: Patrick McHardy Date: Thu Dec 3 12:16:35 2009 +0100 net: fib_rules: allow to delete local rule Allow to delete the local rule and recreate it with a higher priority. This can be used to force packets with a local destination out on the wire instead of routing them to loopback. Additionally this patch allows to recreate rules with a priority of 0. Combined with the previous patch to allow oif classification, a socket can be bound to the desired interface and packets routed to the wire like this: # move local rule to lower priority ip rule add pref 1000 lookup local ip rule del pref 0 # route packets of sockets bound to eth0 to the wire independant # of the destination address ip rule add pref 100 oif eth0 lookup 100 ip route add default dev eth0 table 100 Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/core/fib_rules.c | 2 +- net/ipv4/fib_rules.c | 2 +- net/ipv6/fib6_rules.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index d1a70ad4b54..ef0e7d9e664 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -287,7 +287,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) rule->flags = frh->flags; rule->table = frh_get_table(frh, tb); - if (!rule->pref && ops->default_pref) + if (!tb[FRA_PRIORITY] && ops->default_pref) rule->pref = ops->default_pref(ops); err = -EINVAL; diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 835262c2b86..1239ed23cab 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -284,7 +284,7 @@ static int fib_default_rules_init(struct fib_rules_ops *ops) { int err; - err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, FIB_RULE_PERMANENT); + err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, 0); if (err < 0) return err; err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0); diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 00a7a5e4ac9..3b38f49f2c2 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -276,7 +276,7 @@ static int fib6_rules_net_init(struct net *net) INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list); err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0, - RT6_TABLE_LOCAL, FIB_RULE_PERMANENT); + RT6_TABLE_LOCAL, 0); if (err) goto out_fib6_rules_ops; -- cgit v1.2.3 From 8153a10c08f1312af563bb92532002e46d3f504a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 3 Dec 2009 01:25:58 +0000 Subject: ipv4 05/05: add sysctl to accept packets with local source addresses commit 8ec1e0ebe26087bfc5c0394ada5feb5758014fc8 Author: Patrick McHardy Date: Thu Dec 3 12:16:35 2009 +0100 ipv4: add sysctl to accept packets with local source addresses Change fib_validate_source() to accept packets with a local source address when the "accept_local" sysctl is set for the incoming inet device. Combined with the previous patches, this allows to communicate between multiple local interfaces over the wire. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 6 ++++++ include/linux/inetdevice.h | 1 + include/linux/sysctl.h | 1 + kernel/sysctl_check.c | 1 + net/ipv4/devinet.c | 1 + net/ipv4/fib_frontend.c | 11 +++++++---- 6 files changed, 17 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 989f5538b8d..006b39dec87 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -731,6 +731,12 @@ accept_source_route - BOOLEAN default TRUE (router) FALSE (host) +accept_local - BOOLEAN + Accept packets with local source addresses. In combination with + suitable routing, this can be used to direct packets between two + local interfaces over the wire and have them accepted properly. + default FALSE + rp_filter - INTEGER 0 - No source validation. 1 - Strict mode as defined in RFC3704 Strict Reverse Path diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index eecfa559bfb..699e85c01a4 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -83,6 +83,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) #define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER) #define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \ ACCEPT_SOURCE_ROUTE) +#define IN_DEV_ACCEPT_LOCAL(in_dev) IN_DEV_ORCONF((in_dev), ACCEPT_LOCAL) #define IN_DEV_BOOTP_RELAY(in_dev) IN_DEV_ANDCONF((in_dev), BOOTP_RELAY) #define IN_DEV_LOG_MARTIANS(in_dev) IN_DEV_ORCONF((in_dev), LOG_MARTIANS) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 1e4743ee683..9f047d73a21 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -490,6 +490,7 @@ enum NET_IPV4_CONF_PROMOTE_SECONDARIES=20, NET_IPV4_CONF_ARP_ACCEPT=21, NET_IPV4_CONF_ARP_NOTIFY=22, + NET_IPV4_CONF_ACCEPT_LOCAL=23, __NET_IPV4_CONF_MAX }; diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c index b6e7aaea460..f1d676e4b36 100644 --- a/kernel/sysctl_check.c +++ b/kernel/sysctl_check.c @@ -220,6 +220,7 @@ static const struct trans_ctl_table trans_net_ipv4_conf_vars_table[] = { { NET_IPV4_CONF_PROMOTE_SECONDARIES, "promote_secondaries" }, { NET_IPV4_CONF_ARP_ACCEPT, "arp_accept" }, { NET_IPV4_CONF_ARP_NOTIFY, "arp_notify" }, + { NET_IPV4_CONF_ACCEPT_LOCAL, "accept_local" }, {} }; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c100709d6dd..e3126612fcb 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1468,6 +1468,7 @@ static struct devinet_sysctl_table { DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"), DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE, "accept_source_route"), + DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"), DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"), DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"), DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"), diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 3b373a8b047..3323168ee52 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -241,16 +241,17 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, .iif = oif }; struct fib_result res; - int no_addr, rpf; + int no_addr, rpf, accept_local; int ret; struct net *net; - no_addr = rpf = 0; + no_addr = rpf = accept_local = 0; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); if (in_dev) { no_addr = in_dev->ifa_list == NULL; rpf = IN_DEV_RPFILTER(in_dev); + accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); } rcu_read_unlock(); @@ -260,8 +261,10 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, net = dev_net(dev); if (fib_lookup(net, &fl, &res)) goto last_resort; - if (res.type != RTN_UNICAST) - goto e_inval_res; + if (res.type != RTN_UNICAST) { + if (res.type != RTN_LOCAL || !accept_local) + goto e_inval_res; + } *spec_dst = FIB_RES_PREFSRC(res); fib_combine_itag(itag, &res); #ifdef CONFIG_IP_ROUTE_MULTIPATH -- cgit v1.2.3 From 72ad937abd0a43b7cf2c557ba1f2ec75e608c516 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Dec 2009 02:29:03 +0000 Subject: net: Add support for batching network namespace cleanups - Add exit_list to struct net to support building lists of network namespaces to cleanup. - Add exit_batch to pernet_operations to allow running operations only once during a network namespace exit. Instead of once per network namespace. - Factor opt ops_exit_list and ops_exit_free so the logic with cleanup up a network namespace does not need to be duplicated. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/net_namespace.h | 2 + net/core/net_namespace.c | 122 ++++++++++++++++++++++---------------------- 2 files changed, 63 insertions(+), 61 deletions(-) (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 24a8c5591f6..f307e133d14 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -43,6 +43,7 @@ struct net { #endif struct list_head list; /* list of network namespaces */ struct list_head cleanup_list; /* namespaces on death row */ + struct list_head exit_list; /* Use only net_mutex */ struct proc_dir_entry *proc_net; struct proc_dir_entry *proc_net_stat; @@ -236,6 +237,7 @@ struct pernet_operations { struct list_head list; int (*init)(struct net *net); void (*exit)(struct net *net); + void (*exit_batch)(struct list_head *net_exit_list); int *id; size_t size; }; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 9679ad292da..6c7f6e04dbb 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -70,6 +70,36 @@ static void ops_free(const struct pernet_operations *ops, struct net *net) } } +static void ops_exit_list(const struct pernet_operations *ops, + struct list_head *net_exit_list) +{ + struct net *net; + if (ops->exit) { + list_for_each_entry(net, net_exit_list, exit_list) + ops->exit(net); + } + if (&ops->list == first_device) { + LIST_HEAD(dev_kill_list); + rtnl_lock(); + list_for_each_entry(net, net_exit_list, exit_list) + unregister_netdevices(net, &dev_kill_list); + unregister_netdevice_many(&dev_kill_list); + rtnl_unlock(); + } + if (ops->exit_batch) + ops->exit_batch(net_exit_list); +} + +static void ops_free_list(const struct pernet_operations *ops, + struct list_head *net_exit_list) +{ + struct net *net; + if (ops->size && ops->id) { + list_for_each_entry(net, net_exit_list, exit_list) + ops_free(ops, net); + } +} + /* * setup_net runs the initializers for the network namespace object. */ @@ -78,6 +108,7 @@ static __net_init int setup_net(struct net *net) /* Must be called with net_mutex held */ const struct pernet_operations *ops, *saved_ops; int error = 0; + LIST_HEAD(net_exit_list); atomic_set(&net->count, 1); @@ -97,21 +128,14 @@ out_undo: /* Walk through the list backwards calling the exit functions * for the pernet modules whose init functions did not fail. */ + list_add(&net->exit_list, &net_exit_list); saved_ops = ops; - list_for_each_entry_continue_reverse(ops, &pernet_list, list) { - if (ops->exit) - ops->exit(net); - if (&ops->list == first_device) { - LIST_HEAD(dev_kill_list); - rtnl_lock(); - unregister_netdevices(net, &dev_kill_list); - unregister_netdevice_many(&dev_kill_list); - rtnl_unlock(); - } - } + list_for_each_entry_continue_reverse(ops, &pernet_list, list) + ops_exit_list(ops, &net_exit_list); + ops = saved_ops; list_for_each_entry_continue_reverse(ops, &pernet_list, list) - ops_free(ops, net); + ops_free_list(ops, &net_exit_list); rcu_barrier(); goto out; @@ -207,6 +231,7 @@ static void cleanup_net(struct work_struct *work) const struct pernet_operations *ops; struct net *net, *tmp; LIST_HEAD(net_kill_list); + LIST_HEAD(net_exit_list); /* Atomically snapshot the list of namespaces to cleanup */ spin_lock_irq(&cleanup_list_lock); @@ -217,8 +242,10 @@ static void cleanup_net(struct work_struct *work) /* Don't let anyone else find us. */ rtnl_lock(); - list_for_each_entry(net, &net_kill_list, cleanup_list) + list_for_each_entry(net, &net_kill_list, cleanup_list) { list_del_rcu(&net->list); + list_add_tail(&net->exit_list, &net_exit_list); + } rtnl_unlock(); /* @@ -229,27 +256,12 @@ static void cleanup_net(struct work_struct *work) synchronize_rcu(); /* Run all of the network namespace exit methods */ - list_for_each_entry_reverse(ops, &pernet_list, list) { - if (ops->exit) { - list_for_each_entry(net, &net_kill_list, cleanup_list) - ops->exit(net); - } - if (&ops->list == first_device) { - LIST_HEAD(dev_kill_list); - rtnl_lock(); - list_for_each_entry(net, &net_kill_list, cleanup_list) - unregister_netdevices(net, &dev_kill_list); - unregister_netdevice_many(&dev_kill_list); - rtnl_unlock(); - } - } + list_for_each_entry_reverse(ops, &pernet_list, list) + ops_exit_list(ops, &net_exit_list); + /* Free the net generic variables */ - list_for_each_entry_reverse(ops, &pernet_list, list) { - if (ops->size && ops->id) { - list_for_each_entry(net, &net_kill_list, cleanup_list) - ops_free(ops, net); - } - } + list_for_each_entry_reverse(ops, &pernet_list, list) + ops_free_list(ops, &net_exit_list); mutex_unlock(&net_mutex); @@ -259,8 +271,8 @@ static void cleanup_net(struct work_struct *work) rcu_barrier(); /* Finally it is safe to free my network namespace structure */ - list_for_each_entry_safe(net, tmp, &net_kill_list, cleanup_list) { - list_del_init(&net->cleanup_list); + list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { + list_del_init(&net->exit_list); net_free(net); } } @@ -348,8 +360,9 @@ pure_initcall(net_ns_init); static int __register_pernet_operations(struct list_head *list, struct pernet_operations *ops) { - struct net *net, *undo_net; + struct net *net; int error; + LIST_HEAD(net_exit_list); list_add_tail(&ops->list, list); if (ops->init || (ops->id && ops->size)) { @@ -357,6 +370,7 @@ static int __register_pernet_operations(struct list_head *list, error = ops_init(ops, net); if (error) goto out_undo; + list_add_tail(&net->exit_list, &net_exit_list); } } return 0; @@ -364,36 +378,21 @@ static int __register_pernet_operations(struct list_head *list, out_undo: /* If I have an error cleanup all namespaces I initialized */ list_del(&ops->list); - if (ops->exit) { - for_each_net(undo_net) { - if (net_eq(undo_net, net)) - goto undone; - ops->exit(undo_net); - } - } -undone: - if (ops->size && ops->id) { - for_each_net(undo_net) { - if (net_eq(undo_net, net)) - goto freed; - ops_free(ops, undo_net); - } - } -freed: + ops_exit_list(ops, &net_exit_list); + ops_free_list(ops, &net_exit_list); return error; } static void __unregister_pernet_operations(struct pernet_operations *ops) { struct net *net; + LIST_HEAD(net_exit_list); list_del(&ops->list); - if (ops->exit) - for_each_net(net) - ops->exit(net); - if (ops->id && ops->size) - for_each_net(net) - ops_free(ops, net); + for_each_net(net) + list_add_tail(&net->exit_list, &net_exit_list); + ops_exit_list(ops, &net_exit_list); + ops_free_list(ops, &net_exit_list); } #else @@ -411,9 +410,10 @@ static int __register_pernet_operations(struct list_head *list, static void __unregister_pernet_operations(struct pernet_operations *ops) { - if (ops->exit) - ops->exit(&init_net); - ops_free(ops, &init_net); + LIST_HEAD(net_exit_list); + list_add(&init_net.exit_list, &net_exit_list); + ops_exit_list(ops, &net_exit_list); + ops_free_list(ops, &net_exit_list); } #endif /* CONFIG_NET_NS */ -- cgit v1.2.3 From 04dc7f6be3a7b308f8545bb45772c9fb75f71aca Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Dec 2009 02:29:04 +0000 Subject: net: Move network device exit batching Move network device exit batching from a special case in net_namespace.c to using common mechanisms in dev.c Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/core/dev.c | 25 +++++++++++++++++++++++++ net/core/net_namespace.c | 24 ------------------------ 2 files changed, 25 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index e3e18dee0bd..0913a08a87d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5766,8 +5766,33 @@ static void __net_exit default_device_exit(struct net *net) rtnl_unlock(); } +static void __net_exit default_device_exit_batch(struct list_head *net_list) +{ + /* At exit all network devices most be removed from a network + * namespace. Do this in the reverse order of registeration. + * Do this across as many network namespaces as possible to + * improve batching efficiency. + */ + struct net_device *dev; + struct net *net; + LIST_HEAD(dev_kill_list); + + rtnl_lock(); + list_for_each_entry(net, net_list, exit_list) { + for_each_netdev_reverse(net, dev) { + if (dev->rtnl_link_ops) + dev->rtnl_link_ops->dellink(dev, &dev_kill_list); + else + unregister_netdevice_queue(dev, &dev_kill_list); + } + } + unregister_netdevice_many(&dev_kill_list); + rtnl_unlock(); +} + static struct pernet_operations __net_initdata default_device_ops = { .exit = default_device_exit, + .exit_batch = default_device_exit_batch, }; /* diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 6c7f6e04dbb..4026a4cff93 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -8,10 +8,8 @@ #include #include #include -#include #include #include -#include /* * Our network namespace constructor/destructor lists @@ -29,20 +27,6 @@ EXPORT_SYMBOL(init_net); #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ -static void unregister_netdevices(struct net *net, struct list_head *list) -{ - struct net_device *dev; - /* At exit all network devices most be removed from a network - * namespace. Do this in the reverse order of registeration. - */ - for_each_netdev_reverse(net, dev) { - if (dev->rtnl_link_ops) - dev->rtnl_link_ops->dellink(dev, list); - else - unregister_netdevice_queue(dev, list); - } -} - static int ops_init(const struct pernet_operations *ops, struct net *net) { int err; @@ -78,14 +62,6 @@ static void ops_exit_list(const struct pernet_operations *ops, list_for_each_entry(net, net_exit_list, exit_list) ops->exit(net); } - if (&ops->list == first_device) { - LIST_HEAD(dev_kill_list); - rtnl_lock(); - list_for_each_entry(net, net_exit_list, exit_list) - unregister_netdevices(net, &dev_kill_list); - unregister_netdevice_many(&dev_kill_list); - rtnl_unlock(); - } if (ops->exit_batch) ops->exit_batch(net_exit_list); } -- cgit v1.2.3 From d79d792ef9f99cca463b6619a93e860d1c833a6e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Dec 2009 02:29:05 +0000 Subject: net: Allow xfrm_user_net_exit to batch efficiently. xfrm.nlsk is provided by the xfrm_user module and is access via rcu from other parts of the xfrm code. Add xfrm.nlsk_stash a copy of xfrm.nlsk that will never be set to NULL. This allows the synchronize_net and netlink_kernel_release to be deferred until a whole batch of xfrm.nlsk sockets have been set to NULL. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/netns/xfrm.h | 1 + net/xfrm/xfrm_user.c | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 1ba912749ca..56f8e5585df 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h @@ -43,6 +43,7 @@ struct netns_xfrm { struct work_struct policy_hash_work; struct sock *nlsk; + struct sock *nlsk_stash; u32 sysctl_aevent_etime; u32 sysctl_aevent_rseqth; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index fb42d778d27..1ada6186933 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2721,22 +2721,24 @@ static int __net_init xfrm_user_net_init(struct net *net) xfrm_netlink_rcv, NULL, THIS_MODULE); if (nlsk == NULL) return -ENOMEM; + net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */ rcu_assign_pointer(net->xfrm.nlsk, nlsk); return 0; } -static void __net_exit xfrm_user_net_exit(struct net *net) +static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list) { - struct sock *nlsk = net->xfrm.nlsk; - - rcu_assign_pointer(net->xfrm.nlsk, NULL); - synchronize_rcu(); - netlink_kernel_release(nlsk); + struct net *net; + list_for_each_entry(net, net_exit_list, exit_list) + rcu_assign_pointer(net->xfrm.nlsk, NULL); + synchronize_net(); + list_for_each_entry(net, net_exit_list, exit_list) + netlink_kernel_release(net->xfrm.nlsk_stash); } static struct pernet_operations xfrm_user_net_ops = { - .init = xfrm_user_net_init, - .exit = xfrm_user_net_exit, + .init = xfrm_user_net_init, + .exit_batch = xfrm_user_net_exit, }; static int __init xfrm_user_init(void) -- cgit v1.2.3 From 3a765edadb28cc736d185f67d1ba6bedcc85f4b9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Dec 2009 02:29:06 +0000 Subject: netns: Add an explicit rcu_barrier to unregister_pernet_{device|subsys} This allows namespace exit methods to batch work that comes requires an rcu barrier using call_rcu without having to treat the unregister_pernet_operations cases specially. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/core/net_namespace.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 4026a4cff93..bd8c4712ea2 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -413,8 +413,11 @@ again: } } error = __register_pernet_operations(list, ops); - if (error && ops->id) - ida_remove(&net_generic_ids, *ops->id); + if (error) { + rcu_barrier(); + if (ops->id) + ida_remove(&net_generic_ids, *ops->id); + } return error; } @@ -423,6 +426,7 @@ static void unregister_pernet_operations(struct pernet_operations *ops) { __unregister_pernet_operations(ops); + rcu_barrier(); if (ops->id) ida_remove(&net_generic_ids, *ops->id); } -- cgit v1.2.3 From e9c5158ac26affd5d8ce006521bdfb7148090e18 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Dec 2009 12:22:55 -0800 Subject: net: Allow fib_rule_unregister to batch Refactor the code so fib_rules_register always takes a template instead of the actual fib_rules_ops structure that will be used. This is required for network namespace support so 2 out of the 3 callers already do this, it allows the error handling to be made common, and it allows fib_rules_unregister to free the template for hte caller. Modify fib_rules_unregister to use call_rcu instead of syncrhonize_rcu to allw multiple namespaces to be cleaned up in the same rcu grace period. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/fib_rules.h | 3 ++- net/core/fib_rules.c | 36 +++++++++++++++++++++++++++++++++--- net/decnet/dn_rules.c | 22 ++++++++++++---------- net/ipv4/fib_rules.c | 12 +++--------- net/ipv6/fib6_rules.c | 22 +++++++--------------- 5 files changed, 57 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index d4e875a58f8..c07ac9650eb 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -66,6 +66,7 @@ struct fib_rules_ops { struct list_head rules_list; struct module *owner; struct net *fro_net; + struct rcu_head rcu; }; #define FRA_GENERIC_POLICY \ @@ -102,7 +103,7 @@ static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla) return frh->table; } -extern int fib_rules_register(struct fib_rules_ops *); +extern struct fib_rules_ops *fib_rules_register(struct fib_rules_ops *, struct net *); extern void fib_rules_unregister(struct fib_rules_ops *); extern void fib_rules_cleanup_ops(struct fib_rules_ops *); diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index ef0e7d9e664..02a3b2c69c1 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -72,7 +72,7 @@ static void flush_route_cache(struct fib_rules_ops *ops) ops->flush_cache(ops); } -int fib_rules_register(struct fib_rules_ops *ops) +static int __fib_rules_register(struct fib_rules_ops *ops) { int err = -EEXIST; struct fib_rules_ops *o; @@ -102,6 +102,28 @@ errout: return err; } +struct fib_rules_ops * +fib_rules_register(struct fib_rules_ops *tmpl, struct net *net) +{ + struct fib_rules_ops *ops; + int err; + + ops = kmemdup(tmpl, sizeof (*ops), GFP_KERNEL); + if (ops == NULL) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&ops->rules_list); + ops->fro_net = net; + + err = __fib_rules_register(ops); + if (err) { + kfree(ops); + ops = ERR_PTR(err); + } + + return ops; +} + EXPORT_SYMBOL_GPL(fib_rules_register); void fib_rules_cleanup_ops(struct fib_rules_ops *ops) @@ -115,6 +137,15 @@ void fib_rules_cleanup_ops(struct fib_rules_ops *ops) } EXPORT_SYMBOL_GPL(fib_rules_cleanup_ops); +static void fib_rules_put_rcu(struct rcu_head *head) +{ + struct fib_rules_ops *ops = container_of(head, struct fib_rules_ops, rcu); + struct net *net = ops->fro_net; + + release_net(net); + kfree(ops); +} + void fib_rules_unregister(struct fib_rules_ops *ops) { struct net *net = ops->fro_net; @@ -124,8 +155,7 @@ void fib_rules_unregister(struct fib_rules_ops *ops) fib_rules_cleanup_ops(ops); spin_unlock(&net->rules_mod_lock); - synchronize_rcu(); - release_net(net); + call_rcu(&ops->rcu, fib_rules_put_rcu); } EXPORT_SYMBOL_GPL(fib_rules_unregister); diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 72495f25269..7466c546f28 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -33,7 +33,7 @@ #include #include -static struct fib_rules_ops dn_fib_rules_ops; +static struct fib_rules_ops *dn_fib_rules_ops; struct dn_fib_rule { @@ -56,7 +56,7 @@ int dn_fib_lookup(struct flowi *flp, struct dn_fib_res *res) }; int err; - err = fib_rules_lookup(&dn_fib_rules_ops, flp, 0, &arg); + err = fib_rules_lookup(dn_fib_rules_ops, flp, 0, &arg); res->r = arg.rule; return err; @@ -217,9 +217,9 @@ static u32 dn_fib_rule_default_pref(struct fib_rules_ops *ops) struct list_head *pos; struct fib_rule *rule; - if (!list_empty(&dn_fib_rules_ops.rules_list)) { - pos = dn_fib_rules_ops.rules_list.next; - if (pos->next != &dn_fib_rules_ops.rules_list) { + if (!list_empty(&dn_fib_rules_ops->rules_list)) { + pos = dn_fib_rules_ops->rules_list.next; + if (pos->next != &dn_fib_rules_ops->rules_list) { rule = list_entry(pos->next, struct fib_rule, list); if (rule->pref) return rule->pref - 1; @@ -234,7 +234,7 @@ static void dn_fib_rule_flush_cache(struct fib_rules_ops *ops) dn_rt_cache_flush(-1); } -static struct fib_rules_ops dn_fib_rules_ops = { +static struct fib_rules_ops dn_fib_rules_ops_template = { .family = AF_DECnet, .rule_size = sizeof(struct dn_fib_rule), .addr_size = sizeof(u16), @@ -247,21 +247,23 @@ static struct fib_rules_ops dn_fib_rules_ops = { .flush_cache = dn_fib_rule_flush_cache, .nlgroup = RTNLGRP_DECnet_RULE, .policy = dn_fib_rule_policy, - .rules_list = LIST_HEAD_INIT(dn_fib_rules_ops.rules_list), .owner = THIS_MODULE, .fro_net = &init_net, }; void __init dn_fib_rules_init(void) { - BUG_ON(fib_default_rule_add(&dn_fib_rules_ops, 0x7fff, + dn_fib_rules_ops = + fib_rules_register(&dn_fib_rules_ops_template, &init_net); + BUG_ON(IS_ERR(dn_fib_rules_ops)); + BUG_ON(fib_default_rule_add(dn_fib_rules_ops, 0x7fff, RT_TABLE_MAIN, 0)); - fib_rules_register(&dn_fib_rules_ops); } void __exit dn_fib_rules_cleanup(void) { - fib_rules_unregister(&dn_fib_rules_ops); + fib_rules_unregister(dn_fib_rules_ops); + rcu_barrier(); } diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 1239ed23cab..ca2d07b1c70 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -301,13 +301,9 @@ int __net_init fib4_rules_init(struct net *net) int err; struct fib_rules_ops *ops; - ops = kmemdup(&fib4_rules_ops_template, sizeof(*ops), GFP_KERNEL); - if (ops == NULL) - return -ENOMEM; - INIT_LIST_HEAD(&ops->rules_list); - ops->fro_net = net; - - fib_rules_register(ops); + ops = fib_rules_register(&fib4_rules_ops_template, net); + if (IS_ERR(ops)) + return PTR_ERR(ops); err = fib_default_rules_init(ops); if (err < 0) @@ -318,12 +314,10 @@ int __net_init fib4_rules_init(struct net *net) fail: /* also cleans all rules already added */ fib_rules_unregister(ops); - kfree(ops); return err; } void __net_exit fib4_rules_exit(struct net *net) { fib_rules_unregister(net->ipv4.rules_ops); - kfree(net->ipv4.rules_ops); } diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 3b38f49f2c2..b7aa7c64cc4 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -264,16 +264,14 @@ static struct fib_rules_ops fib6_rules_ops_template = { static int fib6_rules_net_init(struct net *net) { + struct fib_rules_ops *ops; int err = -ENOMEM; - net->ipv6.fib6_rules_ops = kmemdup(&fib6_rules_ops_template, - sizeof(*net->ipv6.fib6_rules_ops), - GFP_KERNEL); - if (!net->ipv6.fib6_rules_ops) - goto out; + ops = fib_rules_register(&fib6_rules_ops_template, net); + if (IS_ERR(ops)) + return PTR_ERR(ops); + net->ipv6.fib6_rules_ops = ops; - net->ipv6.fib6_rules_ops->fro_net = net; - INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list); err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0, RT6_TABLE_LOCAL, 0); @@ -283,25 +281,19 @@ static int fib6_rules_net_init(struct net *net) err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0); if (err) - goto out_fib6_default_rule_add; + goto out_fib6_rules_ops; - err = fib_rules_register(net->ipv6.fib6_rules_ops); - if (err) - goto out_fib6_default_rule_add; out: return err; -out_fib6_default_rule_add: - fib_rules_cleanup_ops(net->ipv6.fib6_rules_ops); out_fib6_rules_ops: - kfree(net->ipv6.fib6_rules_ops); + fib_rules_unregister(ops); goto out; } static void fib6_rules_net_exit(struct net *net) { fib_rules_unregister(net->ipv6.fib6_rules_ops); - kfree(net->ipv6.fib6_rules_ops); } static struct pernet_operations fib6_rules_net_ops = { -- cgit v1.2.3 From 575f4cd5a5b639457747434dbe18d175fa767db4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Dec 2009 02:29:08 +0000 Subject: net: Use rcu lookups in inet_twsk_purge. While we are looking up entries to free there is no reason to take the lock in inet_twsk_purge. We have to drop locks and restart occassionally anyway so adding a few more in case we get on the wrong list because of a timewait move is no big deal. At the same time not taking the lock for long periods of time is much more polite to the rest of the users of the hash table. In my test configuration of killing 4k network namespaces this change causes 4k back to back runs of inet_twsk_purge on an empty hash table to go from roughly 20.7s to 3.3s, and the total time to destroy 4k network namespaces goes from roughly 44s to 3.3s. Signed-off-by: Eric W. Biederman Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/inet_timewait_sock.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 1f5d508bb18..d38ca7c77b9 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -427,31 +427,40 @@ void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo, struct inet_timewait_sock *tw; struct sock *sk; struct hlist_nulls_node *node; - int h; + unsigned int slot; - local_bh_disable(); - 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); + for (slot = 0; slot <= hashinfo->ehash_mask; slot++) { + struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; +restart_rcu: + rcu_read_lock(); restart: - spin_lock(lock); - sk_nulls_for_each(sk, node, &head->twchain) { - + sk_nulls_for_each_rcu(sk, node, &head->twchain) { tw = inet_twsk(sk); if (!net_eq(twsk_net(tw), net) || tw->tw_family != family) continue; - atomic_inc(&tw->tw_refcnt); - spin_unlock(lock); + if (unlikely(!atomic_inc_not_zero(&tw->tw_refcnt))) + continue; + + if (unlikely(!net_eq(twsk_net(tw), net) || + tw->tw_family != family)) { + inet_twsk_put(tw); + goto restart; + } + + rcu_read_unlock(); inet_twsk_deschedule(tw, twdr); inet_twsk_put(tw); - - goto restart; + goto restart_rcu; } - spin_unlock(lock); + /* If the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != slot) + goto restart; + rcu_read_unlock(); } - local_bh_enable(); } EXPORT_SYMBOL_GPL(inet_twsk_purge); -- cgit v1.2.3 From b099ce2602d806deb41caaa578731848995cdb2a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 3 Dec 2009 02:29:09 +0000 Subject: net: Batch inet_twsk_purge This function walks the whole hashtable so there is no point in passing it a network namespace. Instead I purge all timewait sockets from dead network namespaces that I find. If the namespace is one of the once I am trying to purge I am guaranteed no new timewait sockets can be formed so this will get them all. If the namespace is one I am not acting for it might form a few more but I will call inet_twsk_purge again and shortly to get rid of them. In any even if the network namespace is dead timewait sockets are useless. Move the calls of inet_twsk_purge into batch_exit routines so that if I am killing a bunch of namespaces at once I will just call inet_twsk_purge once and save a lot of redundant unnecessary work. My simple 4k network namespace exit test the cleanup time dropped from roughly 8.2s to 1.6s. While the time spent running inet_twsk_purge fell to about 2ms. 1ms for ipv4 and 1ms for ipv6. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/net/inet_timewait_sock.h | 6 +++--- net/ipv4/inet_timewait_sock.c | 10 +++++----- net/ipv4/tcp_ipv4.c | 11 ++++++++--- net/ipv6/tcp_ipv6.c | 11 ++++++++--- 4 files changed, 24 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 773b10fa38e..4fd007f34dd 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -212,14 +212,14 @@ extern void inet_twsk_schedule(struct inet_timewait_sock *tw, extern void inet_twsk_deschedule(struct inet_timewait_sock *tw, struct inet_timewait_death_row *twdr); -extern void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo, +extern void inet_twsk_purge(struct inet_hashinfo *hashinfo, struct inet_timewait_death_row *twdr, int family); static inline struct net *twsk_net(const struct inet_timewait_sock *twsk) { #ifdef CONFIG_NET_NS - return twsk->tw_net; + return rcu_dereference(twsk->tw_net); #else return &init_net; #endif @@ -229,7 +229,7 @@ static inline void twsk_net_set(struct inet_timewait_sock *twsk, struct net *net) { #ifdef CONFIG_NET_NS - twsk->tw_net = net; + rcu_assign_pointer(twsk->tw_net, net); #endif } #endif /* _INET_TIMEWAIT_SOCK_ */ diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index d38ca7c77b9..31f931ef3da 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -421,7 +421,7 @@ out: EXPORT_SYMBOL_GPL(inet_twdr_twcal_tick); -void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo, +void inet_twsk_purge(struct inet_hashinfo *hashinfo, struct inet_timewait_death_row *twdr, int family) { struct inet_timewait_sock *tw; @@ -436,15 +436,15 @@ restart_rcu: restart: sk_nulls_for_each_rcu(sk, node, &head->twchain) { tw = inet_twsk(sk); - if (!net_eq(twsk_net(tw), net) || - tw->tw_family != family) + if ((tw->tw_family != family) || + atomic_read(&twsk_net(tw)->count)) continue; if (unlikely(!atomic_inc_not_zero(&tw->tw_refcnt))) continue; - if (unlikely(!net_eq(twsk_net(tw), net) || - tw->tw_family != family)) { + if (unlikely((tw->tw_family != family) || + atomic_read(&twsk_net(tw)->count))) { inet_twsk_put(tw); goto restart; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 59c911f3889..fee9aabd5aa 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2529,12 +2529,17 @@ static int __net_init tcp_sk_init(struct net *net) static void __net_exit tcp_sk_exit(struct net *net) { inet_ctl_sock_destroy(net->ipv4.tcp_sock); - inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET); +} + +static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list) +{ + inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET); } static struct pernet_operations __net_initdata tcp_sk_ops = { - .init = tcp_sk_init, - .exit = tcp_sk_exit, + .init = tcp_sk_init, + .exit = tcp_sk_exit, + .exit_batch = tcp_sk_exit_batch, }; void __init tcp_v4_init(void) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fc0a4e5895e..aadd7cef73b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2184,12 +2184,17 @@ static int tcpv6_net_init(struct net *net) static void tcpv6_net_exit(struct net *net) { inet_ctl_sock_destroy(net->ipv6.tcp_sk); - inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6); +} + +static void tcpv6_net_exit_batch(struct list_head *net_exit_list) +{ + inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); } static struct pernet_operations tcpv6_net_ops = { - .init = tcpv6_net_init, - .exit = tcpv6_net_exit, + .init = tcpv6_net_init, + .exit = tcpv6_net_exit, + .exit_batch = tcpv6_net_exit_batch, }; int __init tcpv6_init(void) -- cgit v1.2.3 From fc4a7489663250360cd40d5adf06a08d1c5d54df Mon Sep 17 00:00:00 2001 From: Patrick Mullaney Date: Thu, 3 Dec 2009 15:59:22 -0800 Subject: netdevice: provide common routine for macvlan and vlan operstate management Provide common routine for the transition of operational state for a leaf device during a root device transition. Signed-off-by: Patrick Mullaney Acked-by: Arnd Bergmann Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 24 +++--------------------- include/linux/netdevice.h | 3 +++ net/8021q/vlan.c | 29 ++++------------------------- net/core/dev.c | 27 +++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 46 deletions(-) (limited to 'net') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 93c3e6edf70..21a9c9ab4b3 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -582,25 +582,6 @@ static void macvlan_port_destroy(struct net_device *dev) kfree(port); } -static void macvlan_transfer_operstate(struct net_device *dev) -{ - struct macvlan_dev *vlan = netdev_priv(dev); - const struct net_device *lowerdev = vlan->lowerdev; - - if (lowerdev->operstate == IF_OPER_DORMANT) - netif_dormant_on(dev); - else - netif_dormant_off(dev); - - if (netif_carrier_ok(lowerdev)) { - if (!netif_carrier_ok(dev)) - netif_carrier_on(dev); - } else { - if (netif_carrier_ok(dev)) - netif_carrier_off(dev); - } -} - static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) { if (tb[IFLA_ADDRESS]) { @@ -693,7 +674,7 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, return err; list_add_tail(&vlan->list, &port->vlans); - macvlan_transfer_operstate(dev); + netif_stacked_transfer_operstate(lowerdev, dev); return 0; } @@ -768,7 +749,8 @@ static int macvlan_device_event(struct notifier_block *unused, switch (event) { case NETDEV_CHANGE: list_for_each_entry(vlan, &port->vlans, list) - macvlan_transfer_operstate(vlan->dev); + netif_stacked_transfer_operstate(vlan->lowerdev, + vlan->dev); break; case NETDEV_FEAT_CHANGE: list_for_each_entry(vlan, &port->vlans, list) { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index daf13d36749..a3fccc85b1a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1981,6 +1981,9 @@ unsigned long netdev_increment_features(unsigned long all, unsigned long one, unsigned long mask); unsigned long netdev_fix_features(unsigned long features, const char *name); +void netif_stacked_transfer_operstate(const struct net_device *rootdev, + struct net_device *dev); + static inline int net_gso_ok(int features, int gso_type) { int feature = gso_type << NETIF_F_GSO_SHIFT; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index ec3769295da..33f90e7362c 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -184,27 +184,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) dev_put(real_dev); } -static void vlan_transfer_operstate(const struct net_device *dev, - struct net_device *vlandev) -{ - /* Have to respect userspace enforced dormant state - * of real device, also must allow supplicant running - * on VLAN device - */ - if (dev->operstate == IF_OPER_DORMANT) - netif_dormant_on(vlandev); - else - netif_dormant_off(vlandev); - - if (netif_carrier_ok(dev)) { - if (!netif_carrier_ok(vlandev)) - netif_carrier_on(vlandev); - } else { - if (netif_carrier_ok(vlandev)) - netif_carrier_off(vlandev); - } -} - int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) { const char *name = real_dev->name; @@ -262,7 +241,7 @@ int register_vlan_dev(struct net_device *dev) /* Account for reference in struct vlan_dev_info */ dev_hold(real_dev); - vlan_transfer_operstate(real_dev, dev); + netif_stacked_transfer_operstate(real_dev, dev); linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ /* So, got the sucker initialized, now lets place @@ -453,7 +432,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, if (!vlandev) continue; - vlan_transfer_operstate(dev, vlandev); + netif_stacked_transfer_operstate(dev, vlandev); } break; @@ -511,7 +490,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, vlan = vlan_dev_info(vlandev); if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) dev_change_flags(vlandev, flgs & ~IFF_UP); - vlan_transfer_operstate(dev, vlandev); + netif_stacked_transfer_operstate(dev, vlandev); } break; @@ -529,7 +508,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, vlan = vlan_dev_info(vlandev); if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) dev_change_flags(vlandev, flgs | IFF_UP); - vlan_transfer_operstate(dev, vlandev); + netif_stacked_transfer_operstate(dev, vlandev); } break; diff --git a/net/core/dev.c b/net/core/dev.c index 0913a08a87d..c36a17aafcf 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4900,6 +4900,33 @@ unsigned long netdev_fix_features(unsigned long features, const char *name) } EXPORT_SYMBOL(netdev_fix_features); +/** + * netif_stacked_transfer_operstate - transfer operstate + * @rootdev: the root or lower level device to transfer state from + * @dev: the device to transfer operstate to + * + * Transfer operational state from root to device. This is normally + * called when a stacking relationship exists between the root + * device and the device(a leaf device). + */ +void netif_stacked_transfer_operstate(const struct net_device *rootdev, + struct net_device *dev) +{ + if (rootdev->operstate == IF_OPER_DORMANT) + netif_dormant_on(dev); + else + netif_dormant_off(dev); + + if (netif_carrier_ok(rootdev)) { + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + } else { + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); + } +} +EXPORT_SYMBOL(netif_stacked_transfer_operstate); + /** * register_netdevice - register a network device * @dev: device to register -- cgit v1.2.3 From 49d09007879ce7bee36ab453c73e97c00adce884 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Dec 2009 16:06:13 -0800 Subject: tcp: diag: Dont report negative values for rx queue Both netlink and /proc/net/tcp interfaces can report transient negative values for rx queue. ss -> State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB -6 6 127.0.0.1:45956 127.0.0.1:3333 netstat -> tcp 4294967290 6 127.0.0.1:37784 127.0.0.1:3333 ESTABLISHED This is because we dont lock socket while computing tp->rcv_nxt - tp->copied_seq, and another CPU can update copied_seq before rcv_next in RX path. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_diag.c | 2 +- net/ipv4/tcp_ipv4.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index fcbcd4ff6c5..939edb3b8e4 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -27,7 +27,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, r->idiag_rqueue = sk->sk_ack_backlog; r->idiag_wqueue = sk->sk_max_ack_backlog; } else { - r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq; + r->idiag_rqueue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); r->idiag_wqueue = tp->write_seq - tp->snd_una; } if (info != NULL) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fee9aabd5aa..29002ab26e0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2318,6 +2318,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) __be32 src = inet->inet_rcv_saddr; __u16 destp = ntohs(inet->inet_dport); __u16 srcp = ntohs(inet->inet_sport); + int rx_queue; if (icsk->icsk_pending == ICSK_TIME_RETRANS) { timer_active = 1; @@ -2333,12 +2334,19 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) timer_expires = jiffies; } + if (sk->sk_state == TCP_LISTEN) + rx_queue = sk->sk_ack_backlog; + else + /* + * because we dont lock socket, we might find a transient negative value + */ + rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); + seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " "%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n", i, src, srcp, dest, destp, sk->sk_state, tp->write_seq - tp->snd_una, - sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog : - (tp->rcv_nxt - tp->copied_seq), + rx_queue, timer_active, jiffies_to_clock_t(timer_expires - jiffies), icsk->icsk_retransmits, -- cgit v1.2.3 From 13475a30b66cdb9250a34052c19ac98847373030 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Dec 2009 22:31:19 +0000 Subject: tcp: connect() race with timewait reuse Its currently possible that several threads issuing a connect() find the same timewait socket and try to reuse it, leading to list corruptions. Condition for bug is that these threads bound their socket on same address/port of to-be-find timewait socket, and connected to same target. (SO_REUSEADDR needed) To fix this problem, we could unhash timewait socket while holding ehash lock, to make sure lookups/changes will be serialized. Only first thread finds the timewait socket, other ones find the established socket and return an EADDRNOTAVAIL error. This second version takes into account Evgeniy's review and makes sure inet_twsk_put() is called outside of locked sections. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_timewait_sock.h | 2 ++ net/ipv4/inet_hashtables.c | 10 +++++++--- net/ipv4/inet_timewait_sock.c | 38 ++++++++++++++++++++++++++++---------- net/ipv6/inet6_hashtables.c | 15 ++++++++++----- 4 files changed, 47 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 4fd007f34dd..b801ade2295 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -199,6 +199,8 @@ static inline __be32 inet_rcv_saddr(const struct sock *sk) extern void inet_twsk_put(struct inet_timewait_sock *tw); +extern int inet_twsk_unhash(struct inet_timewait_sock *tw); + extern struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 94ef51aa5bc..21e5e32d8c6 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -286,6 +286,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_nulls_node *node; struct inet_timewait_sock *tw; + int twrefcnt = 0; spin_lock(lock); @@ -318,20 +319,23 @@ unique: sk->sk_hash = hash; WARN_ON(!sk_unhashed(sk)); __sk_nulls_add_node_rcu(sk, &head->chain); + if (tw) { + twrefcnt = inet_twsk_unhash(tw); + NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); + } spin_unlock(lock); + if (twrefcnt) + inet_twsk_put(tw); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); if (twp) { *twp = tw; - NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); } else if (tw) { /* Silly. Should hash-dance instead... */ inet_twsk_deschedule(tw, death_row); - NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); inet_twsk_put(tw); } - return 0; not_unique: diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 31f931ef3da..11a107a5af4 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -14,22 +14,33 @@ #include #include + +/* + * unhash a timewait socket from established hash + * lock must be hold by caller + */ +int inet_twsk_unhash(struct inet_timewait_sock *tw) +{ + if (hlist_nulls_unhashed(&tw->tw_node)) + return 0; + + hlist_nulls_del_rcu(&tw->tw_node); + sk_nulls_node_init(&tw->tw_node); + return 1; +} + /* Must be called with locally disabled BHs. */ static void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo) { struct inet_bind_hashbucket *bhead; struct inet_bind_bucket *tb; + int refcnt; /* Unlink from established hashes. */ spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); spin_lock(lock); - if (hlist_nulls_unhashed(&tw->tw_node)) { - spin_unlock(lock); - return; - } - hlist_nulls_del_rcu(&tw->tw_node); - sk_nulls_node_init(&tw->tw_node); + refcnt = inet_twsk_unhash(tw); spin_unlock(lock); /* Disassociate with bind bucket. */ @@ -37,9 +48,12 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw, hashinfo->bhash_size)]; spin_lock(&bhead->lock); tb = tw->tw_tb; - __hlist_del(&tw->tw_bind_node); - tw->tw_tb = NULL; - inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); + if (tb) { + __hlist_del(&tw->tw_bind_node); + tw->tw_tb = NULL; + inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); + refcnt++; + } spin_unlock(&bhead->lock); #ifdef SOCK_REFCNT_DEBUG if (atomic_read(&tw->tw_refcnt) != 1) { @@ -47,7 +61,10 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw, tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt)); } #endif - inet_twsk_put(tw); + while (refcnt) { + inet_twsk_put(tw); + refcnt--; + } } static noinline void inet_twsk_free(struct inet_timewait_sock *tw) @@ -92,6 +109,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, tw->tw_tb = icsk->icsk_bind_hash; WARN_ON(!icsk->icsk_bind_hash); inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); + atomic_inc(&tw->tw_refcnt); spin_unlock(&bhead->lock); spin_lock(lock); diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 00c6a3e6cdd..c813e294ec0 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -223,6 +223,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_nulls_node *node; struct inet_timewait_sock *tw; + int twrefcnt = 0; spin_lock(lock); @@ -250,19 +251,23 @@ unique: * in hash table socket with a funny identity. */ inet->inet_num = lport; inet->inet_sport = htons(lport); + sk->sk_hash = hash; WARN_ON(!sk_unhashed(sk)); __sk_nulls_add_node_rcu(sk, &head->chain); - sk->sk_hash = hash; + if (tw) { + twrefcnt = inet_twsk_unhash(tw); + NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); + } spin_unlock(lock); + if (twrefcnt) + inet_twsk_put(tw); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - if (twp != NULL) { + if (twp) { *twp = tw; - NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); - } else if (tw != NULL) { + } else if (tw) { /* Silly. Should hash-dance instead... */ inet_twsk_deschedule(tw, death_row); - NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); inet_twsk_put(tw); } -- cgit v1.2.3 From 47e1c323069bcef0acb8a2b48921688573f5ca63 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 3 Dec 2009 00:49:01 +0000 Subject: tcp: fix a timewait refcnt race After TCP RCU conversion, tw->tw_refcnt should not be set to 1 in inet_twsk_alloc(). It allows a RCU reader to get this timewait socket, while we not yet stabilized it. Only choice we have is to set tw_refcnt to 0 in inet_twsk_alloc(), then atomic_add() it later, once everything is done. Location of this atomic_add() is tricky, because we dont want another writer to find this timewait in ehash, while tw_refcnt is still zero ! Thanks to Kapil Dakhane tests and reports. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/inet_timewait_sock.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 11a107a5af4..0fdf45e4c90 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -109,7 +109,6 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, tw->tw_tb = icsk->icsk_bind_hash; WARN_ON(!icsk->icsk_bind_hash); inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); - atomic_inc(&tw->tw_refcnt); spin_unlock(&bhead->lock); spin_lock(lock); @@ -119,13 +118,22 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, * Should be done before removing sk from established chain * because readers are lockless and search established first. */ - atomic_inc(&tw->tw_refcnt); inet_twsk_add_node_rcu(tw, &ehead->twchain); /* Step 3: Remove SK from established hash. */ if (__sk_nulls_del_node_init_rcu(sk)) sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + /* + * Notes : + * - We initially set tw_refcnt to 0 in inet_twsk_alloc() + * - We add one reference for the bhash link + * - We add one reference for the ehash link + * - We want this refcnt update done before allowing other + * threads to find this tw in ehash chain. + */ + atomic_add(1 + 1 + 1, &tw->tw_refcnt); + spin_unlock(lock); } @@ -157,7 +165,12 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat tw->tw_transparent = inet->transparent; tw->tw_prot = sk->sk_prot_creator; twsk_net_set(tw, hold_net(sock_net(sk))); - atomic_set(&tw->tw_refcnt, 1); + /* + * Because we use RCU lookups, we should not set tw_refcnt + * to a non null value before everything is setup for this + * timewait socket. + */ + atomic_set(&tw->tw_refcnt, 0); inet_twsk_dead_node_init(tw); __module_get(tw->tw_prot->owner); } -- cgit v1.2.3 From 1014eb6ec95b18f890101e99385f05539c0c2f01 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Tue, 24 Nov 2009 10:47:08 -0800 Subject: WE: Fix set events not propagated I've just noticed that some events are no longer propagated for some wireless drivers. Basically, SET request with a extra payload for driver without commit handler. The fix is pretty simple, see attached. Actually, a few lines below this line, you will see that the event generation for simple SET (iwpoint-less ?) is done properly, and this other event generation does not need fixing. Signed-off-by: Jean Tourrilhes Signed-off-by: John W. Linville --- net/wireless/wext-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index a4e5ddc8d4f..6033785f56c 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -802,7 +802,8 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, } /* Generate an event to notify listeners of the change */ - if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { + if ((descr->flags & IW_DESCR_FLAG_EVENT) && + ((err == 0) || (err == -EIWCOMMIT))) { union iwreq_data *data = (union iwreq_data *) iwp; if (descr->flags & IW_DESCR_FLAG_RESTRICT) -- cgit v1.2.3 From 914828fad09269292be1bfa3dfbe78d064f76068 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 29 Nov 2009 14:29:42 +0200 Subject: mac80211: Fix TX status reporting for injected data frames An earlier optimization on removing unnecessary traffic on cooked monitor interfaces ("mac80211: reduce the amount of unnecessary traffic on cooked monitor interfaces ") ended up removing quite a bit more than just unnecessary traffic. It was not supposed to remove TX status reporting for injected frames, but ended up doing it by checking the injected flag in skb->cb only after that field had been cleared with memset.. Fix this by taking a local copy of the injected flag before skb->cb is cleared. This broke user space applications that depend on getting TX status notifications for injected data frames. For example, STA inactivity poll from hostapd did not work and ended up kicking out stations even if they were still present. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/status.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 9f91fd8e6ef..d78f36c64c7 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -148,6 +148,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) struct net_device *prev_dev = NULL; struct sta_info *sta; int retry_count = -1, i; + bool injected; for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { /* the HW cannot have attempted that rate */ @@ -297,6 +298,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) /* for now report the total retry_count */ rthdr->data_retries = retry_count; + /* Need to make a copy before skb->cb gets cleared */ + injected = !!(info->flags & IEEE80211_TX_CTL_INJECTED); + /* XXX: is this sufficient for BPF? */ skb_set_mac_header(skb, 0); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -311,7 +315,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) continue; if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && - !(info->flags & IEEE80211_TX_CTL_INJECTED) && + !injected && (type == IEEE80211_FTYPE_DATA)) continue; -- cgit v1.2.3 From 269ac5fd2d75b118d76a2291e28796527db2f3f8 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 1 Dec 2009 10:47:15 +0200 Subject: cfg80211: indent regulatory messages with spaces The regulatory messages in syslog look weird: kernel: cfg80211: Regulatory domain: US kernel: ^I(start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp) kernel: ^I(2402000 KHz - 2472000 KHz @ 40000 KHz), (600 mBi, 2700 mBm) kernel: ^I(5170000 KHz - 5190000 KHz @ 40000 KHz), (600 mBi, 2300 mBm) kernel: ^I(5190000 KHz - 5210000 KHz @ 40000 KHz), (600 mBi, 2300 mBm) kernel: ^I(5210000 KHz - 5230000 KHz @ 40000 KHz), (600 mBi, 2300 mBm) kernel: ^I(5230000 KHz - 5330000 KHz @ 40000 KHz), (600 mBi, 2300 mBm) kernel: ^I(5735000 KHz - 5835000 KHz @ 40000 KHz), (600 mBi, 3000 mBm) Indent them with four spaces instead of the tab character to get prettier output. Signed-off-by: Kalle Valo Acked: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1f33017737f..c01470e7de1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1931,7 +1931,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) const struct ieee80211_freq_range *freq_range = NULL; const struct ieee80211_power_rule *power_rule = NULL; - printk(KERN_INFO "\t(start_freq - end_freq @ bandwidth), " + printk(KERN_INFO " (start_freq - end_freq @ bandwidth), " "(max_antenna_gain, max_eirp)\n"); for (i = 0; i < rd->n_reg_rules; i++) { @@ -1944,7 +1944,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) * in certain regions */ if (power_rule->max_antenna_gain) - printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " + printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), " "(%d mBi, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, @@ -1952,7 +1952,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) power_rule->max_antenna_gain, power_rule->max_eirp); else - printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " + printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), " "(N/A, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, -- cgit v1.2.3 From d29cecda036f251aee4947f47eea0fe9ed8cc931 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 4 Dec 2009 14:25:43 -0800 Subject: mac80211: fix reorder buffer release My patch "mac80211: correctly place aMPDU RX reorder code" uses an skb queue for MPDUs that were released from the buffer. I intentially didn't initialise and use the skb queue's spinlock, but in this place forgot that the code variant that doesn't touch the spinlock is needed. Thanks to Christian Lamparter for quickly spotting the bug in the backtrace Reinette reported. Reported-by: Reinette Chatre Bug-identified-by: Christian Lamparter Tested-by: Reinette Chatre Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4ed60ae81b9..f237df40837 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -570,7 +570,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, rate = &sband->bitrates[status->rate_idx]; tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; - skb_queue_tail(frames, skb); + __skb_queue_tail(frames, skb); no_frame: tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); -- cgit v1.2.3