From a46f025d053e47b9ce602f53f6d30e94d304a51c Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Wed, 16 Apr 2008 14:02:04 -0700 Subject: mac80211: Fix n-band association problem There are two structures named wmm_info and wmm_param, they are used while parsing the beacon frame. (Check the function ieee802_11_parse_elems). Certain APs like D-link does not set the fifth bit in WMM IE. While sending the association request to n-only ap it checks for wmm_ie. If it is set then only ieee80211_ht_cap is sent during association request. So n-only association fails. And this patch fixes this problem by copying the wmm_info to wmm_ie, which enables the "wmm" flag in iee80211_send_assoc. Signed-off-by: Abhijeet Kolekar Acked-by: Ron Rindjunsky Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6b75cb6c630..c0a5345c8a6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2709,7 +2709,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->wmm_ie_len = elems.wmm_param_len + 2; } else bss->wmm_ie_len = 0; - } else if (!elems.wmm_param && bss->wmm_ie) { + } else if (elems.wmm_info && + (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_info_len || + memcmp(bss->wmm_ie, elems.wmm_info, elems.wmm_info_len))) { + /* As for certain AP's Fifth bit is not set in WMM IE in + * beacon frames.So while parsing the beacon frame the + * wmm_info structure is used instead of wmm_param. + * wmm_info structure was never used to set bss->wmm_ie. + * This code fixes this problem by copying the WME + * information from wmm_info to bss->wmm_ie and enabling + * n-band association. + */ + kfree(bss->wmm_ie); + bss->wmm_ie = kmalloc(elems.wmm_info_len + 2, GFP_ATOMIC); + if (bss->wmm_ie) { + memcpy(bss->wmm_ie, elems.wmm_info - 2, + elems.wmm_info_len + 2); + bss->wmm_ie_len = elems.wmm_info_len + 2; + } else + bss->wmm_ie_len = 0; + } else if (!elems.wmm_param && !elems.wmm_info && bss->wmm_ie) { kfree(bss->wmm_ie); bss->wmm_ie = NULL; bss->wmm_ie_len = 0; -- cgit v1.2.3 From 1ebebea8e844d01c80b93b8ee4d696ee7c0cbc27 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 23 Apr 2008 11:47:15 +0400 Subject: mac80211: Fix race between ieee80211_rx_bss_put and lookup routines. The put routine first decrements the users counter and then (if it is zero) locks the sta_bss_lock and removes one from the list and the hash. Thus, any of ieee80211_sta_config_auth, ieee80211_rx_bss_get or ieee80211_rx_mesh_bss_get can race with it by finding a bss that is about to get kfree-ed. Using atomic_dec_and_lock in ieee80211_rx_bss_put takes care of this race. Signed-off-by: Pavel Emelyanov Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c0a5345c8a6..a5e5c31c23a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2248,10 +2248,13 @@ static void ieee80211_rx_bss_put(struct net_device *dev, struct ieee80211_sta_bss *bss) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - if (!atomic_dec_and_test(&bss->users)) + + local_bh_disable(); + if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { + local_bh_enable(); return; + } - spin_lock_bh(&local->sta_bss_lock); __ieee80211_rx_bss_hash_del(dev, bss); list_del(&bss->list); spin_unlock_bh(&local->sta_bss_lock); -- cgit v1.2.3 From 13d8fd2d15fdd492078bedb9fde87c901a4e4df0 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 23 Apr 2008 12:51:28 +0300 Subject: net/mac80211/rx.c: fix off-by-one This patch fixes an off-by-one in net/mac80211/rx.c introduced by commit 8318d78a44d49ac1edf2bdec7299de3617c4232e (cfg80211 API for channels/bitrates, mac80211 and driver conversion) and spotted by the Coverity checker. Signed-off-by: Adrian Bunk 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 52e4554fdde..02f436a8606 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2170,7 +2170,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_supported_band *sband; if (status->band < 0 || - status->band > IEEE80211_NUM_BANDS) { + status->band >= IEEE80211_NUM_BANDS) { WARN_ON(1); return; } -- cgit v1.2.3 From 0da926f05748d273e7b2b673b0de21629ae9acdd Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 23 Apr 2008 13:45:12 +0300 Subject: mac80211: fix use before check of Qdisc length This patch fixes use of Qdisc length in requeue function, before we checked the reference is valid. (Adrian Bunk's catch) Signed-off-by: Ron Rindjunsky Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- net/mac80211/wme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 4e94e4026e7..64faa3dc488 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -709,7 +709,7 @@ void ieee80211_requeue(struct ieee80211_local *local, int queue) struct ieee80211_sched_data *q = qdisc_priv(root_qd); struct Qdisc *qdisc = q->queues[queue]; struct sk_buff *skb = NULL; - u32 len = qdisc->q.qlen; + u32 len; if (!qdisc || !qdisc->dequeue) return; -- cgit v1.2.3 From c9c1014b2bd014c7ec037bbb6f58818162fdb265 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 23 Apr 2008 22:10:48 -0700 Subject: [RTNETLINK]: Fix bogus ASSERT_RTNL warning ASSERT_RTNL uses mutex_trylock to test whether the rtnl_mutex is held. This bogus warnings when running in atomic context, which f.e. happens when adding secondary unicast addresses through macvlan or vlan or when synchronizing multicast addresses from wireless devices. Mid-term we might want to consider moving all address updates to process context since the locking seems overly complicated, for now just fix the bogus warning by changing ASSERT_RTNL to use mutex_is_locked(). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index bc39e417694..cf857c4dc7b 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -82,6 +82,11 @@ int rtnl_trylock(void) return mutex_trylock(&rtnl_mutex); } +int rtnl_is_locked(void) +{ + return mutex_is_locked(&rtnl_mutex); +} + static struct rtnl_link *rtnl_msg_handlers[NPROTO]; static inline int rtm_msgindex(int msgtype) @@ -1402,6 +1407,7 @@ 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); -- cgit v1.2.3 From 3d36696024499aef19dbf24a781e91a24fbbe4af Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 24 Apr 2008 00:59:25 -0700 Subject: [AF_UNIX] Initialise UNIX sockets before general device initcalls When drivers call request_module(), it tries to do something with UNIX sockets and triggers a 'runaway loop modprobe net-pf-1' warning. Avoid this by initialising AF_UNIX support earlier. Signed-off-by: David Woodhouse Signed-off-by: David S. Miller --- net/unix/af_unix.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2851d0d1504..63ed69ffad9 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2193,7 +2193,11 @@ static void __exit af_unix_exit(void) unregister_pernet_subsys(&unix_net_ops); } -module_init(af_unix_init); +/* Earlier than device_initcall() so that other drivers invoking + request_module() don't end up in a loop when modprobe tries + to use a UNIX socket. But later than subsys_initcall() because + we depend on stuff initialised there */ +fs_initcall(af_unix_init); module_exit(af_unix_exit); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5e659e4cb0eedacdc1f621a61e400a4611ddef8a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 24 Apr 2008 01:02:16 -0700 Subject: [NET]: Fix heavy stack usage in seq_file output routines. Plan C: we can follow the Al Viro's proposal about %n like in this patch. The same applies to udp, fib (the /proc/net/route file), rt_cache and sctp debug. This is minus ~150-200 bytes for each. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/fib_hash.c | 17 +++++++++-------- net/ipv4/fib_trie.c | 18 ++++++++++-------- net/ipv4/route.c | 11 ++++++----- net/ipv4/tcp_ipv4.c | 36 +++++++++++++++++++----------------- net/ipv4/udp.c | 15 ++++++++------- net/sctp/objcnt.c | 9 ++++----- 6 files changed, 56 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 02088deb046..2e2fc3376ac 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -1003,7 +1003,7 @@ static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi) static int fib_seq_show(struct seq_file *seq, void *v) { struct fib_iter_state *iter; - char bf[128]; + int len; __be32 prefix, mask; unsigned flags; struct fib_node *f; @@ -1025,18 +1025,19 @@ static int fib_seq_show(struct seq_file *seq, void *v) mask = FZ_MASK(iter->zone); flags = fib_flag_trans(fa->fa_type, mask, fi); if (fi) - snprintf(bf, sizeof(bf), - "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", + seq_printf(seq, + "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u%n", fi->fib_dev ? fi->fib_dev->name : "*", prefix, fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority, mask, (fi->fib_advmss ? fi->fib_advmss + 40 : 0), fi->fib_window, - fi->fib_rtt >> 3); + fi->fib_rtt >> 3, &len); else - snprintf(bf, sizeof(bf), - "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", - prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0); - seq_printf(seq, "%-127s\n", bf); + seq_printf(seq, + "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u%n", + prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0, &len); + + seq_printf(seq, "%*s\n", 127 - len, ""); out: return 0; } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index ea294fffb9c..4b02d14e7ab 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2602,15 +2602,16 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) list_for_each_entry_rcu(fa, &li->falh, fa_list) { const struct fib_info *fi = fa->fa_info; unsigned flags = fib_flag_trans(fa->fa_type, mask, fi); - char bf[128]; + int len; if (fa->fa_type == RTN_BROADCAST || fa->fa_type == RTN_MULTICAST) continue; if (fi) - snprintf(bf, sizeof(bf), - "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", + seq_printf(seq, + "%s\t%08X\t%08X\t%04X\t%d\t%u\t" + "%d\t%08X\t%d\t%u\t%u%n", fi->fib_dev ? fi->fib_dev->name : "*", prefix, fi->fib_nh->nh_gw, flags, 0, 0, @@ -2619,14 +2620,15 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) (fi->fib_advmss ? fi->fib_advmss + 40 : 0), fi->fib_window, - fi->fib_rtt >> 3); + fi->fib_rtt >> 3, &len); else - snprintf(bf, sizeof(bf), - "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", + seq_printf(seq, + "*\t%08X\t%08X\t%04X\t%d\t%u\t" + "%d\t%08X\t%d\t%u\t%u%n", prefix, 0, flags, 0, 0, 0, - mask, 0, 0, 0); + mask, 0, 0, 0, &len); - seq_printf(seq, "%-127s\n", bf); + seq_printf(seq, "%*s\n", 127 - len, ""); } } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 780e9484c82..ce25a13f343 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -367,10 +367,10 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) "HHUptod\tSpecDst"); else { struct rtable *r = v; - char temp[256]; + int len; - sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t" - "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X", + seq_printf(seq, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t" + "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", r->u.dst.dev ? r->u.dst.dev->name : "*", (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway, r->rt_flags, atomic_read(&r->u.dst.__refcnt), @@ -384,8 +384,9 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1, r->u.dst.hh ? (r->u.dst.hh->hh_output == dev_queue_xmit) : 0, - r->rt_spec_dst); - seq_printf(seq, "%-127s\n", temp); + r->rt_spec_dst, &len); + + seq_printf(seq, "%*s\n", 127 - len, ""); } return 0; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 776615180b9..0e9bc120707 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2255,13 +2255,13 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) } static void get_openreq4(struct sock *sk, struct request_sock *req, - char *tmpbuf, int i, int uid) + struct seq_file *f, int i, int uid, int *len) { const struct inet_request_sock *ireq = inet_rsk(req); int ttd = req->expires - jiffies; - sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p", + seq_printf(f, "%4d: %08X:%04X %08X:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n", i, ireq->loc_addr, ntohs(inet_sk(sk)->sport), @@ -2276,10 +2276,11 @@ static void get_openreq4(struct sock *sk, struct request_sock *req, 0, /* non standard timer */ 0, /* open_requests have no inode */ atomic_read(&sk->sk_refcnt), - req); + req, + len); } -static void get_tcp4_sock(struct sock *sk, char *tmpbuf, int i) +static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) { int timer_active; unsigned long timer_expires; @@ -2305,8 +2306,8 @@ static void get_tcp4_sock(struct sock *sk, char *tmpbuf, int i) timer_expires = jiffies; } - sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " - "%08X %5d %8d %lu %d %p %u %u %u %u %d", + seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " + "%08X %5d %8d %lu %d %p %u %u %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 : @@ -2322,11 +2323,12 @@ static void get_tcp4_sock(struct sock *sk, char *tmpbuf, int i) icsk->icsk_ack.ato, (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, tp->snd_cwnd, - tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh); + tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh, + len); } static void get_timewait4_sock(struct inet_timewait_sock *tw, - char *tmpbuf, int i) + struct seq_file *f, int i, int *len) { __be32 dest, src; __u16 destp, srcp; @@ -2340,11 +2342,11 @@ static void get_timewait4_sock(struct inet_timewait_sock *tw, destp = ntohs(tw->tw_dport); srcp = ntohs(tw->tw_sport); - sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p", + seq_printf(f, "%4d: %08X:%04X %08X:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p%n", i, src, srcp, dest, destp, tw->tw_substate, 0, 0, 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0, - atomic_read(&tw->tw_refcnt), tw); + atomic_read(&tw->tw_refcnt), tw, len); } #define TMPSZ 150 @@ -2352,7 +2354,7 @@ static void get_timewait4_sock(struct inet_timewait_sock *tw, static int tcp4_seq_show(struct seq_file *seq, void *v) { struct tcp_iter_state* st; - char tmpbuf[TMPSZ + 1]; + int len; if (v == SEQ_START_TOKEN) { seq_printf(seq, "%-*s\n", TMPSZ - 1, @@ -2366,16 +2368,16 @@ static int tcp4_seq_show(struct seq_file *seq, void *v) switch (st->state) { case TCP_SEQ_STATE_LISTENING: case TCP_SEQ_STATE_ESTABLISHED: - get_tcp4_sock(v, tmpbuf, st->num); + get_tcp4_sock(v, seq, st->num, &len); break; case TCP_SEQ_STATE_OPENREQ: - get_openreq4(st->syn_wait_sk, v, tmpbuf, st->num, st->uid); + get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len); break; case TCP_SEQ_STATE_TIME_WAIT: - get_timewait4_sock(v, tmpbuf, st->num); + get_timewait4_sock(v, seq, st->num, &len); break; } - seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); + seq_printf(seq, "%*s\n", TMPSZ - 1 - len, ""); out: return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b053ac79527..1f535e31518 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1619,7 +1619,8 @@ void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) } /* ------------------------------------------------------------------------ */ -static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) +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; @@ -1627,13 +1628,13 @@ static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) __u16 destp = ntohs(inet->dport); __u16 srcp = ntohs(inet->sport); - sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", + seq_printf(f, "%4d: %08X:%04X %08X:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p%n", bucket, src, srcp, dest, destp, sp->sk_state, atomic_read(&sp->sk_wmem_alloc), atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); + atomic_read(&sp->sk_refcnt), sp, len); } int udp4_seq_show(struct seq_file *seq, void *v) @@ -1644,11 +1645,11 @@ int udp4_seq_show(struct seq_file *seq, void *v) "rx_queue tr tm->when retrnsmt uid timeout " "inode"); else { - char tmpbuf[129]; struct udp_iter_state *state = seq->private; + int len; - udp4_format_sock(v, tmpbuf, state->bucket); - seq_printf(seq, "%-127s\n", tmpbuf); + udp4_format_sock(v, seq, state->bucket, &len); + seq_printf(seq, "%*s\n", 127 - len ,""); } return 0; } diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c index cfeb07ea1b0..f73ec0ea93b 100644 --- a/net/sctp/objcnt.c +++ b/net/sctp/objcnt.c @@ -83,13 +83,12 @@ static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { */ static int sctp_objcnt_seq_show(struct seq_file *seq, void *v) { - int i; - char temp[128]; + int i, len; i = (int)*(loff_t *)v; - sprintf(temp, "%s: %d", sctp_dbg_objcnt[i].label, - atomic_read(sctp_dbg_objcnt[i].counter)); - seq_printf(seq, "%-127s\n", temp); + seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label, + atomic_read(sctp_dbg_objcnt[i].counter), &len); + seq_printf(seq, "%*s\n", 127 - len, ""); return 0; } -- cgit v1.2.3