#if IS_ENABLED(CONFIG_NET_DSA)
struct dsa_switch_tree *dsa_ptr; /* dsa specific data */
#endif
+#if IS_ENABLED(CONFIG_TIPC)
+ struct tipc_bearer __rcu *tipc_ptr; /* TIPC specific data */
+#endif
void *atalk_ptr; /* AppleTalk link */
struct in_device __rcu *ip_ptr; /* IPv4 specific data */
struct dn_dev __rcu *dn_ptr; /* DECnet specific data */
/**
* struct tipc_bearer - Generic TIPC bearer structure
+ * @dev: ptr to associated network device
* @usr_handle: pointer to additional media-specific information about bearer
* @mtu: max packet size bearer can support
* @lock: spinlock for controlling access to bearer
* care of initializing all other fields.
*/
struct tipc_bearer {
+ struct net_device *dev;
void *usr_handle; /* initalized by media */
u32 mtu; /* initalized by media */
struct tipc_media_addr addr; /* initalized by media */
static int recv_notification(struct notifier_block *nb, unsigned long evt,
void *dv);
+static int recv_msg(struct sk_buff *buf, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev);
+
/*
* Network device notifier info
*/
.priority = 0
};
+static struct packet_type tipc_packet_type __read_mostly = {
+ .type = __constant_htons(ETH_P_TIPC),
+ .func = recv_msg,
+};
+
/**
* eth_media_addr_set - initialize Ethernet media address structure
*
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv;
+ struct tipc_bearer *b_ptr;
if (!net_eq(dev_net(dev), &init_net)) {
kfree_skb(buf);
return NET_RX_DROP;
}
- if (likely(eb_ptr->bearer)) {
+ rcu_read_lock();
+ b_ptr = rcu_dereference(dev->tipc_ptr);
+ if (likely(b_ptr)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
- tipc_recv_msg(buf, eb_ptr->bearer);
+ tipc_recv_msg(buf, b_ptr);
+ rcu_read_unlock();
return NET_RX_SUCCESS;
}
}
+ rcu_read_unlock();
+
kfree_skb(buf);
return NET_RX_DROP;
}
*/
static void setup_media(struct work_struct *work)
{
- struct eth_media *eb_ptr =
- container_of(work, struct eth_media, setup);
-
- dev_add_pack(&eb_ptr->tipc_packet_type);
+ dev_add_pack(&tipc_packet_type);
}
/**
/* Create Ethernet bearer for device */
eb_ptr->dev = dev;
- eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
- eb_ptr->tipc_packet_type.dev = dev;
- eb_ptr->tipc_packet_type.func = recv_msg;
- eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
- INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
INIT_WORK(&eb_ptr->setup, setup_media);
schedule_work(&eb_ptr->setup);
/* Associate TIPC bearer with Ethernet bearer */
+ tb_ptr->dev = dev;
eb_ptr->bearer = tb_ptr;
tb_ptr->usr_handle = (void *)eb_ptr;
memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
tb_ptr->bcast_addr.broadcast = 1;
tb_ptr->mtu = dev->mtu;
eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
+ rcu_assign_pointer(dev->tipc_ptr, tb_ptr);
return 0;
}
struct eth_media *eb_ptr =
container_of(work, struct eth_media, cleanup);
- dev_remove_pack(&eb_ptr->tipc_packet_type);
+ dev_remove_pack(&tipc_packet_type);
dev_put(eb_ptr->dev);
eb_ptr->dev = NULL;
}
eb_ptr->bearer = NULL;
INIT_WORK(&eb_ptr->cleanup, cleanup_media);
schedule_work(&eb_ptr->cleanup);
+ RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL);
}
/**
static int recv_notification(struct notifier_block *nb, unsigned long evt,
void *ptr)
{
+ struct tipc_bearer *b_ptr;
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- struct eth_media *eb_ptr = ð_media_array[0];
- struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA];
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
- while ((eb_ptr->dev != dev)) {
- if (++eb_ptr == stop)
- return NOTIFY_DONE; /* couldn't find device */
- }
- if (!eb_ptr->bearer)
+ rcu_read_lock();
+ b_ptr = rcu_dereference(dev->tipc_ptr);
+ if (!b_ptr) {
+ rcu_read_unlock();
return NOTIFY_DONE; /* bearer had been disabled */
+ }
- eb_ptr->bearer->mtu = dev->mtu;
+ b_ptr->mtu = dev->mtu;
switch (evt) {
case NETDEV_CHANGE:
case NETDEV_DOWN:
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
- tipc_reset_bearer(eb_ptr->bearer);
+ tipc_reset_bearer(b_ptr);
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
- tipc_disable_bearer(eb_ptr->bearer->name);
+ tipc_disable_bearer(b_ptr->name);
break;
}
+ rcu_read_unlock();
+
return NOTIFY_OK;
}
static struct ib_media ib_media_array[MAX_IB_MEDIA];
static int ib_started;
+static int recv_msg(struct sk_buff *buf, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev);
+
+static struct packet_type tipc_packet_type __read_mostly = {
+ .type = __constant_htons(ETH_P_TIPC),
+ .func = recv_msg,
+};
/**
* ib_media_addr_set - initialize Infiniband media address structure
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv;
+ struct tipc_bearer *b_ptr;
if (!net_eq(dev_net(dev), &init_net)) {
kfree_skb(buf);
return NET_RX_DROP;
}
- if (likely(ib_ptr->bearer)) {
+ rcu_read_lock();
+ b_ptr = rcu_dereference(dev->tipc_ptr);
+ if (likely(b_ptr)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
- tipc_recv_msg(buf, ib_ptr->bearer);
+ tipc_recv_msg(buf, b_ptr);
+ rcu_read_unlock();
return NET_RX_SUCCESS;
}
}
+ rcu_read_unlock();
+
kfree_skb(buf);
return NET_RX_DROP;
}
*/
static void setup_media(struct work_struct *work)
{
- struct ib_media *ib_ptr =
- container_of(work, struct ib_media, setup);
-
- dev_add_pack(&ib_ptr->tipc_packet_type);
+ dev_add_pack(&tipc_packet_type);
}
/**
/* Create InfiniBand bearer for device */
ib_ptr->dev = dev;
- ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
- ib_ptr->tipc_packet_type.dev = dev;
- ib_ptr->tipc_packet_type.func = recv_msg;
- ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr;
- INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list));
INIT_WORK(&ib_ptr->setup, setup_media);
schedule_work(&ib_ptr->setup);
/* Associate TIPC bearer with InfiniBand bearer */
+ tb_ptr->dev = dev;
ib_ptr->bearer = tb_ptr;
tb_ptr->usr_handle = (void *)ib_ptr;
memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
tb_ptr->bcast_addr.broadcast = 1;
tb_ptr->mtu = dev->mtu;
ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
+ rcu_assign_pointer(dev->tipc_ptr, tb_ptr);
return 0;
}
struct ib_media *ib_ptr =
container_of(work, struct ib_media, cleanup);
- dev_remove_pack(&ib_ptr->tipc_packet_type);
+ dev_remove_pack(&tipc_packet_type);
dev_put(ib_ptr->dev);
ib_ptr->dev = NULL;
}
ib_ptr->bearer = NULL;
INIT_WORK(&ib_ptr->cleanup, cleanup_bearer);
schedule_work(&ib_ptr->cleanup);
+ RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL);
}
/**
static int recv_notification(struct notifier_block *nb, unsigned long evt,
void *ptr)
{
+ struct tipc_bearer *b_ptr;
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- struct ib_media *ib_ptr = &ib_media_array[0];
- struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA];
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
- while ((ib_ptr->dev != dev)) {
- if (++ib_ptr == stop)
- return NOTIFY_DONE; /* couldn't find device */
- }
- if (!ib_ptr->bearer)
+ rcu_read_lock();
+ b_ptr = rcu_dereference(dev->tipc_ptr);
+ if (!b_ptr) {
+ rcu_read_unlock();
return NOTIFY_DONE; /* bearer had been disabled */
+ }
- ib_ptr->bearer->mtu = dev->mtu;
+ b_ptr->mtu = dev->mtu;
switch (evt) {
case NETDEV_CHANGE:
case NETDEV_DOWN:
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
- tipc_reset_bearer(ib_ptr->bearer);
+ tipc_reset_bearer(b_ptr);
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
- tipc_disable_bearer(ib_ptr->bearer->name);
+ tipc_disable_bearer(b_ptr->name);
break;
}
+ rcu_read_unlock();
+
return NOTIFY_OK;
}