#define ATIF_PROBE_FAIL 2 /* Probe collided */
struct atalk_netrange nets;
struct atalk_iface *next;
+ struct hlist_node hash_node; /* keyed on dev->ifindex */
};
struct atalk_sock {
/* Inter module exports */
/* Give a device find its atif control structure */
-#if IS_ENABLED(CONFIG_ATALK)
-static inline struct atalk_iface *atalk_find_dev(struct net_device *dev)
-{
- return dev->atalk_ptr;
-}
-#endif
+extern struct atalk_iface *atalk_find_dev(struct net_device *dev);
extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev);
extern struct net_device *atrtr_get_dev(struct atalk_addr *sa);
* @vlan_info: VLAN info
* @dsa_ptr: dsa specific data
* @tipc_ptr: TIPC specific data
- * @atalk_ptr: AppleTalk link
* @ip_ptr: IPv4 specific data
* @ip6_ptr: IPv6 specific data
* @ieee80211_ptr: IEEE 802.11 specific data, assign before registering
#if IS_ENABLED(CONFIG_TIPC)
struct tipc_bearer __rcu *tipc_ptr;
#endif
-#if IS_ENABLED(CONFIG_ATALK)
- void *atalk_ptr;
-#endif
#if IS_ENABLED(CONFIG_CFG80211)
struct wireless_dev *ieee80211_ptr;
#endif
#include <linux/termios.h> /* For TIOCOUTQ/INQ */
#include <linux/compat.h>
#include <linux/slab.h>
+#include <linux/hashtable.h>
#include <net/datalink.h>
#include <net/psnap.h>
#include <net/sock.h>
struct atalk_iface *atalk_interfaces;
DEFINE_RWLOCK(atalk_interfaces_lock);
+/* Fast dev->iface lookup, keyed on ifindex. Shares atalk_interfaces_lock with
+ * the atalk_interfaces list, which remains the owner of the iface objects.
+ */
+#define ATALK_IFACE_HASH_BITS 8
+static DEFINE_HASHTABLE(atalk_iface_hash, ATALK_IFACE_HASH_BITS);
+
+/* Find the iface for @dev. Caller must hold atalk_interfaces_lock. */
+static struct atalk_iface *__atalk_find_dev(struct net_device *dev)
+{
+ struct atalk_iface *iface;
+
+ hash_for_each_possible(atalk_iface_hash, iface, hash_node, dev->ifindex)
+ if (iface->dev == dev)
+ return iface;
+ return NULL;
+}
+
+struct atalk_iface *atalk_find_dev(struct net_device *dev)
+{
+ struct atalk_iface *iface;
+
+ read_lock_bh(&atalk_interfaces_lock);
+ iface = __atalk_find_dev(dev);
+ read_unlock_bh(&atalk_interfaces_lock);
+ return iface;
+}
+
/* For probing devices or in a routerless network */
struct atalk_route atrtr_default;
while ((tmp = *iface) != NULL) {
if (tmp->dev == dev) {
*iface = tmp->next;
+ hash_del(&tmp->hash_node);
dev_put(dev);
kfree(tmp);
- dev->atalk_ptr = NULL;
} else
iface = &tmp->next;
}
dev_hold(dev);
iface->dev = dev;
- dev->atalk_ptr = iface;
iface->address = *sa;
iface->status = 0;
write_lock_bh(&atalk_interfaces_lock);
iface->next = atalk_interfaces;
atalk_interfaces = iface;
+ hash_add(atalk_iface_hash, &iface->hash_node, dev->ifindex);
write_unlock_bh(&atalk_interfaces_lock);
out:
return iface;
struct atalk_addr *atalk_find_dev_addr(struct net_device *dev)
{
- struct atalk_iface *iface = dev->atalk_ptr;
- return iface ? &iface->address : NULL;
+ struct atalk_addr *addr = NULL;
+ struct atalk_iface *iface;
+
+ read_lock_bh(&atalk_interfaces_lock);
+ iface = __atalk_find_dev(dev);
+ if (iface)
+ addr = &iface->address;
+ read_unlock_bh(&atalk_interfaces_lock);
+ return addr;
}
static struct atalk_addr *atalk_find_primary(void)
*/
static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev)
{
- struct atalk_iface *iface = dev->atalk_ptr;
+ struct atalk_iface *iface;
+ read_lock_bh(&atalk_interfaces_lock);
+ iface = __atalk_find_dev(dev);
if (!iface || iface->status & ATIF_PROBE)
goto out_err;
node != ATADDR_ANYNODE)
goto out_err;
out:
+ read_unlock_bh(&atalk_interfaces_lock);
return iface;
out_err:
iface = NULL;