diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-06 15:34:06 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-06 15:34:06 (GMT) |
commit | cb4361c1dc29cd870f664c004b1817106fbce0fa (patch) | |
tree | c31533210d738c9074b21b8f31fe0399b39545f0 /net | |
parent | 309361e09ca9e9670dc8664e5d14125bf82078af (diff) | |
parent | fb9e2d887243499b8d28efcf80821c4f6a092395 (diff) | |
download | linux-cb4361c1dc29cd870f664c004b1817106fbce0fa.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (37 commits)
smc91c92_cs: fix the problem of "Unable to find hardware address"
r8169: clean up my printk uglyness
net: Hook up cxgb4 to Kconfig and Makefile
cxgb4: Add main driver file and driver Makefile
cxgb4: Add remaining driver headers and L2T management
cxgb4: Add packet queues and packet DMA code
cxgb4: Add HW and FW support code
cxgb4: Add register, message, and FW definitions
netlabel: Fix several rcu_dereference() calls used without RCU read locks
bonding: fix potential deadlock in bond_uninit()
net: check the length of the socket address passed to connect(2)
stmmac: add documentation for the driver.
stmmac: fix kconfig for crc32 build error
be2net: fix bug in vlan rx path for big endian architecture
be2net: fix flashing on big endian architectures
be2net: fix a bug in flashing the redboot section
bonding: bond_xmit_roundrobin() fix
drivers/net: Add missing unlock
net: gianfar - align BD ring size console messages
net: gianfar - initialize per-queue statistics
...
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap.c | 3 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/sock.c | 3 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 3 | ||||
-rw-r--r-- | net/can/bcm.c | 3 | ||||
-rw-r--r-- | net/ieee802154/af_ieee802154.c | 3 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 1 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 6 | ||||
-rw-r--r-- | net/mac80211/util.c | 18 | ||||
-rw-r--r-- | net/netlabel/netlabel_domainhash.c | 28 | ||||
-rw-r--r-- | net/netlabel/netlabel_unlabeled.c | 66 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 3 | ||||
-rw-r--r-- | net/wireless/reg.c | 12 |
14 files changed, 80 insertions, 78 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7794a2e..99d68c3 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1002,7 +1002,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al BT_DBG("sk %p", sk); - if (!addr || addr->sa_family != AF_BLUETOOTH) + if (!addr || alen < sizeof(addr->sa_family) || + addr->sa_family != AF_BLUETOOTH) return -EINVAL; memset(&la, 0, sizeof(la)); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 7f43976..8ed3c37 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -397,7 +397,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a BT_DBG("sk %p", sk); - if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc)) + if (alen < sizeof(struct sockaddr_rc) || + addr->sa_family != AF_BLUETOOTH) return -EINVAL; lock_sock(sk); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index e5b16b7..ca6b2ad 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -499,7 +499,8 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen BT_DBG("sk %p", sk); - if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco)) + if (alen < sizeof(struct sockaddr_sco) || + addr->sa_family != AF_BLUETOOTH) return -EINVAL; if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) diff --git a/net/can/bcm.c b/net/can/bcm.c index a2dee52..907dc87 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1479,6 +1479,9 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, struct sock *sk = sock->sk; struct bcm_sock *bo = bcm_sk(sk); + if (len < sizeof(*addr)) + return -EINVAL; + if (bo->bound) return -EISCONN; diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 79886d5..c7da600 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -127,6 +127,9 @@ static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, { struct sock *sk = sock->sk; + if (addr_len < sizeof(uaddr->sa_family)) + return -EINVAL; + if (uaddr->sa_family == AF_UNSPEC) return sk->sk_prot->disconnect(sk, flags); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 2ed8571..f713574 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -531,6 +531,8 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, { struct sock *sk = sock->sk; + if (addr_len < sizeof(uaddr->sa_family)) + return -EINVAL; if (uaddr->sa_family == AF_UNSPEC) return sk->sk_prot->disconnect(sk, flags); @@ -574,6 +576,9 @@ int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, int err; long timeo; + if (addr_len < sizeof(uaddr->sa_family)) + return -EINVAL; + lock_sock(sk); if (uaddr->sa_family == AF_UNSPEC) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7a1f1d7..0f8caf6 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1369,6 +1369,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_eat_skb(sk, skb, 0); if (!desc->count) break; + tp->copied_seq = seq; } tp->copied_seq = seq; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 122c113..fefc45c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -392,7 +392,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, if (SN_GT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && action == MPATH_PREQ && - new_metric > mpath->metric)) { + new_metric >= mpath->metric)) { process = false; fresh_info = false; } @@ -612,7 +612,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, cpu_to_le32(orig_sn), 0, target_addr, - cpu_to_le32(target_sn), mpath->next_hop->sta.addr, hopcount, + cpu_to_le32(target_sn), next_hop, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cbe53ed..cfc473e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1991,6 +1991,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; + struct ieee80211_sub_if_data *sdata; unsigned long flags; int i; bool txok; @@ -2029,6 +2030,11 @@ void ieee80211_tx_pending(unsigned long data) if (!txok) break; } + + if (skb_queue_empty(&local->pending[i])) + list_for_each_entry_rcu(sdata, &local->interfaces, list) + netif_tx_wake_queue( + netdev_get_tx_queue(sdata->dev, i)); } spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c453226..53af570 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -279,13 +279,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, /* someone still has this queue stopped */ return; - if (!skb_queue_empty(&local->pending[queue])) + if (skb_queue_empty(&local->pending[queue])) { + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) + netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); + rcu_read_unlock(); + } else tasklet_schedule(&local->tx_pending_tasklet); - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) - netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); - rcu_read_unlock(); } void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, @@ -1097,9 +1097,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) */ res = drv_start(local); if (res) { - WARN(local->suspended, "Harware became unavailable " - "upon resume. This is could be a software issue" - "prior to suspend or a hardware issue\n"); + WARN(local->suspended, "Hardware became unavailable " + "upon resume. This could be a software issue " + "prior to suspend or a hardware issue.\n"); return res; } diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 016ab9c..d37b7f8 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -51,9 +51,12 @@ struct netlbl_domhsh_tbl { }; /* Domain hash table */ -/* XXX - updates should be so rare that having one spinlock for the entire - * hash table should be okay */ +/* updates should be so rare that having one spinlock for the entire hash table + * should be okay */ static DEFINE_SPINLOCK(netlbl_domhsh_lock); +#define netlbl_domhsh_rcu_deref(p) \ + rcu_dereference_check(p, rcu_read_lock_held() || \ + lockdep_is_held(&netlbl_domhsh_lock)) static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; static struct netlbl_dom_map *netlbl_domhsh_def = NULL; @@ -107,7 +110,8 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry) * Description: * This is the hashing function for the domain hash table, it returns the * correct bucket number for the domain. The caller is responsibile for - * calling the rcu_read_[un]lock() functions. + * ensuring that the hash table is protected with either a RCU read lock or the + * hash table lock. * */ static u32 netlbl_domhsh_hash(const char *key) @@ -121,7 +125,7 @@ static u32 netlbl_domhsh_hash(const char *key) for (iter = 0, val = 0, len = strlen(key); iter < len; iter++) val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter]; - return val & (rcu_dereference(netlbl_domhsh)->size - 1); + return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1); } /** @@ -131,7 +135,8 @@ static u32 netlbl_domhsh_hash(const char *key) * Description: * Searches the domain hash table and returns a pointer to the hash table * entry if found, otherwise NULL is returned. The caller is responsibile for - * the rcu hash table locks (i.e. the caller much call rcu_read_[un]lock()). + * ensuring that the hash table is protected with either a RCU read lock or the + * hash table lock. * */ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) @@ -142,7 +147,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) if (domain != NULL) { bkt = netlbl_domhsh_hash(domain); - bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt]; + bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt]; list_for_each_entry_rcu(iter, bkt_list, list) if (iter->valid && strcmp(iter->domain, domain) == 0) return iter; @@ -160,8 +165,8 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) * Searches the domain hash table and returns a pointer to the hash table * entry if an exact match is found, if an exact match is not present in the * hash table then the default entry is returned if valid otherwise NULL is - * returned. The caller is responsibile for the rcu hash table locks - * (i.e. the caller much call rcu_read_[un]lock()). + * returned. The caller is responsibile ensuring that the hash table is + * protected with either a RCU read lock or the hash table lock. * */ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) @@ -170,7 +175,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) entry = netlbl_domhsh_search(domain); if (entry == NULL) { - entry = rcu_dereference(netlbl_domhsh_def); + entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def); if (entry != NULL && !entry->valid) entry = NULL; } @@ -307,8 +312,11 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, struct netlbl_af6list *tmp6; #endif /* IPv6 */ + /* XXX - we can remove this RCU read lock as the spinlock protects the + * entire function, but before we do we need to fixup the + * netlbl_af[4,6]list RCU functions to do "the right thing" with + * respect to rcu_dereference() when only a spinlock is held. */ rcu_read_lock(); - spin_lock(&netlbl_domhsh_lock); if (entry->domain != NULL) entry_old = netlbl_domhsh_search(entry->domain); diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index d7ea2cf..a3d64aa 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -115,6 +115,9 @@ struct netlbl_unlhsh_walk_arg { /* updates should be so rare that having one spinlock for the entire * hash table should be okay */ static DEFINE_SPINLOCK(netlbl_unlhsh_lock); +#define netlbl_unlhsh_rcu_deref(p) \ + rcu_dereference_check(p, rcu_read_lock_held() || \ + lockdep_is_held(&netlbl_unlhsh_lock)) static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL; static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL; @@ -236,15 +239,13 @@ static void netlbl_unlhsh_free_iface(struct rcu_head *entry) * Description: * This is the hashing function for the unlabeled hash table, it returns the * bucket number for the given device/interface. The caller is responsible for - * calling the rcu_read_[un]lock() functions. + * ensuring that the hash table is protected with either a RCU read lock or + * the hash table lock. * */ static u32 netlbl_unlhsh_hash(int ifindex) { - /* this is taken _almost_ directly from - * security/selinux/netif.c:sel_netif_hasfn() as they do pretty much - * the same thing */ - return ifindex & (rcu_dereference(netlbl_unlhsh)->size - 1); + return ifindex & (netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->size - 1); } /** @@ -254,7 +255,8 @@ static u32 netlbl_unlhsh_hash(int ifindex) * Description: * Searches the unlabeled connection hash table and returns a pointer to the * interface entry which matches @ifindex, otherwise NULL is returned. The - * caller is responsible for calling the rcu_read_[un]lock() functions. + * caller is responsible for ensuring that the hash table is protected with + * either a RCU read lock or the hash table lock. * */ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) @@ -264,7 +266,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) struct netlbl_unlhsh_iface *iter; bkt = netlbl_unlhsh_hash(ifindex); - bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt]; + bkt_list = &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]; list_for_each_entry_rcu(iter, bkt_list, list) if (iter->valid && iter->ifindex == ifindex) return iter; @@ -273,33 +275,6 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) } /** - * netlbl_unlhsh_search_iface_def - Search for a matching interface entry - * @ifindex: the network interface - * - * Description: - * Searches the unlabeled connection hash table and returns a pointer to the - * interface entry which matches @ifindex. If an exact match can not be found - * and there is a valid default entry, the default entry is returned, otherwise - * NULL is returned. The caller is responsible for calling the - * rcu_read_[un]lock() functions. - * - */ -static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex) -{ - struct netlbl_unlhsh_iface *entry; - - entry = netlbl_unlhsh_search_iface(ifindex); - if (entry != NULL) - return entry; - - entry = rcu_dereference(netlbl_unlhsh_def); - if (entry != NULL && entry->valid) - return entry; - - return NULL; -} - -/** * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table * @iface: the associated interface entry * @addr: IPv4 address in network byte order @@ -309,8 +284,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex) * Description: * Add a new address entry into the unlabeled connection hash table using the * interface entry specified by @iface. On success zero is returned, otherwise - * a negative value is returned. The caller is responsible for calling the - * rcu_read_[un]lock() functions. + * a negative value is returned. * */ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, @@ -350,8 +324,7 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface, * Description: * Add a new address entry into the unlabeled connection hash table using the * interface entry specified by @iface. On success zero is returned, otherwise - * a negative value is returned. The caller is responsible for calling the - * rcu_read_[un]lock() functions. + * a negative value is returned. * */ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, @@ -392,8 +365,7 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface, * Description: * Add a new, empty, interface entry into the unlabeled connection hash table. * On success a pointer to the new interface entry is returned, on failure NULL - * is returned. The caller is responsible for calling the rcu_read_[un]lock() - * functions. + * is returned. * */ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) @@ -416,10 +388,10 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex) if (netlbl_unlhsh_search_iface(ifindex) != NULL) goto add_iface_failure; list_add_tail_rcu(&iface->list, - &rcu_dereference(netlbl_unlhsh)->tbl[bkt]); + &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]); } else { INIT_LIST_HEAD(&iface->list); - if (rcu_dereference(netlbl_unlhsh_def) != NULL) + if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL) goto add_iface_failure; rcu_assign_pointer(netlbl_unlhsh_def, iface); } @@ -549,8 +521,7 @@ unlhsh_add_return: * * Description: * Remove an IP address entry from the unlabeled connection hash table. - * Returns zero on success, negative values on failure. The caller is - * responsible for calling the rcu_read_[un]lock() functions. + * Returns zero on success, negative values on failure. * */ static int netlbl_unlhsh_remove_addr4(struct net *net, @@ -612,8 +583,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net, * * Description: * Remove an IP address entry from the unlabeled connection hash table. - * Returns zero on success, negative values on failure. The caller is - * responsible for calling the rcu_read_[un]lock() functions. + * Returns zero on success, negative values on failure. * */ static int netlbl_unlhsh_remove_addr6(struct net *net, @@ -1548,8 +1518,10 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, struct netlbl_unlhsh_iface *iface; rcu_read_lock(); - iface = netlbl_unlhsh_search_iface_def(skb->skb_iif); + iface = netlbl_unlhsh_search_iface(skb->skb_iif); if (iface == NULL) + iface = rcu_dereference(netlbl_unlhsh_def); + if (iface == NULL || !iface->valid) goto unlabel_getattr_nolabel; switch (family) { case PF_INET: { diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index acbbae1..7954243 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -683,6 +683,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; + if (alen < sizeof(addr->sa_family)) + return -EINVAL; + if (addr->sa_family == AF_UNSPEC) { sk->sk_state = NETLINK_UNCONNECTED; nlk->dst_pid = 0; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b7604b8..422da20 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -325,7 +325,7 @@ struct reg_regdb_search_request { }; static LIST_HEAD(reg_regdb_search_list); -static DEFINE_SPINLOCK(reg_regdb_search_lock); +static DEFINE_MUTEX(reg_regdb_search_mutex); static void reg_regdb_search(struct work_struct *work) { @@ -333,7 +333,7 @@ static void reg_regdb_search(struct work_struct *work) const struct ieee80211_regdomain *curdom, *regdom; int i, r; - spin_lock(®_regdb_search_lock); + mutex_lock(®_regdb_search_mutex); while (!list_empty(®_regdb_search_list)) { request = list_first_entry(®_regdb_search_list, struct reg_regdb_search_request, @@ -347,18 +347,16 @@ static void reg_regdb_search(struct work_struct *work) r = reg_copy_regd(®dom, curdom); if (r) break; - spin_unlock(®_regdb_search_lock); mutex_lock(&cfg80211_mutex); set_regdom(regdom); mutex_unlock(&cfg80211_mutex); - spin_lock(®_regdb_search_lock); break; } } kfree(request); } - spin_unlock(®_regdb_search_lock); + mutex_unlock(®_regdb_search_mutex); } static DECLARE_WORK(reg_regdb_work, reg_regdb_search); @@ -376,9 +374,9 @@ static void reg_regdb_query(const char *alpha2) memcpy(request->alpha2, alpha2, 2); - spin_lock(®_regdb_search_lock); + mutex_lock(®_regdb_search_mutex); list_add_tail(&request->list, ®_regdb_search_list); - spin_unlock(®_regdb_search_lock); + mutex_unlock(®_regdb_search_mutex); schedule_work(®_regdb_work); } |