diff options
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | net/tipc/bearer.h | 2 | ||||
-rw-r--r-- | net/tipc/eth_media.c | 55 | ||||
-rw-r--r-- | net/tipc/ib_media.c | 54 |
4 files changed, 68 insertions, 46 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9d55e5188b96..0ca8100f9fbc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1283,6 +1283,9 @@ struct net_device { | |||
1283 | #if IS_ENABLED(CONFIG_NET_DSA) | 1283 | #if IS_ENABLED(CONFIG_NET_DSA) |
1284 | struct dsa_switch_tree *dsa_ptr; /* dsa specific data */ | 1284 | struct dsa_switch_tree *dsa_ptr; /* dsa specific data */ |
1285 | #endif | 1285 | #endif |
1286 | #if IS_ENABLED(CONFIG_TIPC) | ||
1287 | struct tipc_bearer __rcu *tipc_ptr; /* TIPC specific data */ | ||
1288 | #endif | ||
1286 | void *atalk_ptr; /* AppleTalk link */ | 1289 | void *atalk_ptr; /* AppleTalk link */ |
1287 | struct in_device __rcu *ip_ptr; /* IPv4 specific data */ | 1290 | struct in_device __rcu *ip_ptr; /* IPv4 specific data */ |
1288 | struct dn_dev __rcu *dn_ptr; /* DECnet specific data */ | 1291 | struct dn_dev __rcu *dn_ptr; /* DECnet specific data */ |
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index e50266aa4d10..91b8d8b92373 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h | |||
@@ -105,6 +105,7 @@ struct tipc_media { | |||
105 | 105 | ||
106 | /** | 106 | /** |
107 | * struct tipc_bearer - Generic TIPC bearer structure | 107 | * struct tipc_bearer - Generic TIPC bearer structure |
108 | * @dev: ptr to associated network device | ||
108 | * @usr_handle: pointer to additional media-specific information about bearer | 109 | * @usr_handle: pointer to additional media-specific information about bearer |
109 | * @mtu: max packet size bearer can support | 110 | * @mtu: max packet size bearer can support |
110 | * @lock: spinlock for controlling access to bearer | 111 | * @lock: spinlock for controlling access to bearer |
@@ -127,6 +128,7 @@ struct tipc_media { | |||
127 | * care of initializing all other fields. | 128 | * care of initializing all other fields. |
128 | */ | 129 | */ |
129 | struct tipc_bearer { | 130 | struct tipc_bearer { |
131 | struct net_device *dev; | ||
130 | void *usr_handle; /* initalized by media */ | 132 | void *usr_handle; /* initalized by media */ |
131 | u32 mtu; /* initalized by media */ | 133 | u32 mtu; /* initalized by media */ |
132 | struct tipc_media_addr addr; /* initalized by media */ | 134 | struct tipc_media_addr addr; /* initalized by media */ |
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 37fb145476ec..c5f685dee15b 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c | |||
@@ -63,6 +63,9 @@ static int eth_started; | |||
63 | 63 | ||
64 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | 64 | static int recv_notification(struct notifier_block *nb, unsigned long evt, |
65 | void *dv); | 65 | void *dv); |
66 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | ||
67 | struct packet_type *pt, struct net_device *orig_dev); | ||
68 | |||
66 | /* | 69 | /* |
67 | * Network device notifier info | 70 | * Network device notifier info |
68 | */ | 71 | */ |
@@ -71,6 +74,11 @@ static struct notifier_block notifier = { | |||
71 | .priority = 0 | 74 | .priority = 0 |
72 | }; | 75 | }; |
73 | 76 | ||
77 | static struct packet_type tipc_packet_type __read_mostly = { | ||
78 | .type = __constant_htons(ETH_P_TIPC), | ||
79 | .func = recv_msg, | ||
80 | }; | ||
81 | |||
74 | /** | 82 | /** |
75 | * eth_media_addr_set - initialize Ethernet media address structure | 83 | * eth_media_addr_set - initialize Ethernet media address structure |
76 | * | 84 | * |
@@ -128,20 +136,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, | |||
128 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | 136 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, |
129 | struct packet_type *pt, struct net_device *orig_dev) | 137 | struct packet_type *pt, struct net_device *orig_dev) |
130 | { | 138 | { |
131 | struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv; | 139 | struct tipc_bearer *b_ptr; |
132 | 140 | ||
133 | if (!net_eq(dev_net(dev), &init_net)) { | 141 | if (!net_eq(dev_net(dev), &init_net)) { |
134 | kfree_skb(buf); | 142 | kfree_skb(buf); |
135 | return NET_RX_DROP; | 143 | return NET_RX_DROP; |
136 | } | 144 | } |
137 | 145 | ||
138 | if (likely(eb_ptr->bearer)) { | 146 | rcu_read_lock(); |
147 | b_ptr = rcu_dereference(dev->tipc_ptr); | ||
148 | if (likely(b_ptr)) { | ||
139 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | 149 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { |
140 | buf->next = NULL; | 150 | buf->next = NULL; |
141 | tipc_recv_msg(buf, eb_ptr->bearer); | 151 | tipc_recv_msg(buf, b_ptr); |
152 | rcu_read_unlock(); | ||
142 | return NET_RX_SUCCESS; | 153 | return NET_RX_SUCCESS; |
143 | } | 154 | } |
144 | } | 155 | } |
156 | rcu_read_unlock(); | ||
157 | |||
145 | kfree_skb(buf); | 158 | kfree_skb(buf); |
146 | return NET_RX_DROP; | 159 | return NET_RX_DROP; |
147 | } | 160 | } |
@@ -151,10 +164,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, | |||
151 | */ | 164 | */ |
152 | static void setup_media(struct work_struct *work) | 165 | static void setup_media(struct work_struct *work) |
153 | { | 166 | { |
154 | struct eth_media *eb_ptr = | 167 | dev_add_pack(&tipc_packet_type); |
155 | container_of(work, struct eth_media, setup); | ||
156 | |||
157 | dev_add_pack(&eb_ptr->tipc_packet_type); | ||
158 | } | 168 | } |
159 | 169 | ||
160 | /** | 170 | /** |
@@ -183,15 +193,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) | |||
183 | 193 | ||
184 | /* Create Ethernet bearer for device */ | 194 | /* Create Ethernet bearer for device */ |
185 | eb_ptr->dev = dev; | 195 | eb_ptr->dev = dev; |
186 | eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); | ||
187 | eb_ptr->tipc_packet_type.dev = dev; | ||
188 | eb_ptr->tipc_packet_type.func = recv_msg; | ||
189 | eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; | ||
190 | INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); | ||
191 | INIT_WORK(&eb_ptr->setup, setup_media); | 196 | INIT_WORK(&eb_ptr->setup, setup_media); |
192 | schedule_work(&eb_ptr->setup); | 197 | schedule_work(&eb_ptr->setup); |
193 | 198 | ||
194 | /* Associate TIPC bearer with Ethernet bearer */ | 199 | /* Associate TIPC bearer with Ethernet bearer */ |
200 | tb_ptr->dev = dev; | ||
195 | eb_ptr->bearer = tb_ptr; | 201 | eb_ptr->bearer = tb_ptr; |
196 | tb_ptr->usr_handle = (void *)eb_ptr; | 202 | tb_ptr->usr_handle = (void *)eb_ptr; |
197 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); | 203 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); |
@@ -200,6 +206,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) | |||
200 | tb_ptr->bcast_addr.broadcast = 1; | 206 | tb_ptr->bcast_addr.broadcast = 1; |
201 | tb_ptr->mtu = dev->mtu; | 207 | tb_ptr->mtu = dev->mtu; |
202 | eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); | 208 | eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); |
209 | rcu_assign_pointer(dev->tipc_ptr, tb_ptr); | ||
203 | return 0; | 210 | return 0; |
204 | } | 211 | } |
205 | 212 | ||
@@ -213,7 +220,7 @@ static void cleanup_media(struct work_struct *work) | |||
213 | struct eth_media *eb_ptr = | 220 | struct eth_media *eb_ptr = |
214 | container_of(work, struct eth_media, cleanup); | 221 | container_of(work, struct eth_media, cleanup); |
215 | 222 | ||
216 | dev_remove_pack(&eb_ptr->tipc_packet_type); | 223 | dev_remove_pack(&tipc_packet_type); |
217 | dev_put(eb_ptr->dev); | 224 | dev_put(eb_ptr->dev); |
218 | eb_ptr->dev = NULL; | 225 | eb_ptr->dev = NULL; |
219 | } | 226 | } |
@@ -232,6 +239,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) | |||
232 | eb_ptr->bearer = NULL; | 239 | eb_ptr->bearer = NULL; |
233 | INIT_WORK(&eb_ptr->cleanup, cleanup_media); | 240 | INIT_WORK(&eb_ptr->cleanup, cleanup_media); |
234 | schedule_work(&eb_ptr->cleanup); | 241 | schedule_work(&eb_ptr->cleanup); |
242 | RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); | ||
235 | } | 243 | } |
236 | 244 | ||
237 | /** | 245 | /** |
@@ -243,21 +251,20 @@ static void disable_media(struct tipc_bearer *tb_ptr) | |||
243 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | 251 | static int recv_notification(struct notifier_block *nb, unsigned long evt, |
244 | void *ptr) | 252 | void *ptr) |
245 | { | 253 | { |
254 | struct tipc_bearer *b_ptr; | ||
246 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 255 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
247 | struct eth_media *eb_ptr = ð_media_array[0]; | ||
248 | struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; | ||
249 | 256 | ||
250 | if (!net_eq(dev_net(dev), &init_net)) | 257 | if (!net_eq(dev_net(dev), &init_net)) |
251 | return NOTIFY_DONE; | 258 | return NOTIFY_DONE; |
252 | 259 | ||
253 | while ((eb_ptr->dev != dev)) { | 260 | rcu_read_lock(); |
254 | if (++eb_ptr == stop) | 261 | b_ptr = rcu_dereference(dev->tipc_ptr); |
255 | return NOTIFY_DONE; /* couldn't find device */ | 262 | if (!b_ptr) { |
256 | } | 263 | rcu_read_unlock(); |
257 | if (!eb_ptr->bearer) | ||
258 | return NOTIFY_DONE; /* bearer had been disabled */ | 264 | return NOTIFY_DONE; /* bearer had been disabled */ |
265 | } | ||
259 | 266 | ||
260 | eb_ptr->bearer->mtu = dev->mtu; | 267 | b_ptr->mtu = dev->mtu; |
261 | 268 | ||
262 | switch (evt) { | 269 | switch (evt) { |
263 | case NETDEV_CHANGE: | 270 | case NETDEV_CHANGE: |
@@ -266,13 +273,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, | |||
266 | case NETDEV_DOWN: | 273 | case NETDEV_DOWN: |
267 | case NETDEV_CHANGEMTU: | 274 | case NETDEV_CHANGEMTU: |
268 | case NETDEV_CHANGEADDR: | 275 | case NETDEV_CHANGEADDR: |
269 | tipc_reset_bearer(eb_ptr->bearer); | 276 | tipc_reset_bearer(b_ptr); |
270 | break; | 277 | break; |
271 | case NETDEV_UNREGISTER: | 278 | case NETDEV_UNREGISTER: |
272 | case NETDEV_CHANGENAME: | 279 | case NETDEV_CHANGENAME: |
273 | tipc_disable_bearer(eb_ptr->bearer->name); | 280 | tipc_disable_bearer(b_ptr->name); |
274 | break; | 281 | break; |
275 | } | 282 | } |
283 | rcu_read_unlock(); | ||
284 | |||
276 | return NOTIFY_OK; | 285 | return NOTIFY_OK; |
277 | } | 286 | } |
278 | 287 | ||
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index 48e1c07842e6..9fdf03cd672b 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c | |||
@@ -62,6 +62,13 @@ struct ib_media { | |||
62 | 62 | ||
63 | static struct ib_media ib_media_array[MAX_IB_MEDIA]; | 63 | static struct ib_media ib_media_array[MAX_IB_MEDIA]; |
64 | static int ib_started; | 64 | static int ib_started; |
65 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | ||
66 | struct packet_type *pt, struct net_device *orig_dev); | ||
67 | |||
68 | static struct packet_type tipc_packet_type __read_mostly = { | ||
69 | .type = __constant_htons(ETH_P_TIPC), | ||
70 | .func = recv_msg, | ||
71 | }; | ||
65 | 72 | ||
66 | /** | 73 | /** |
67 | * ib_media_addr_set - initialize Infiniband media address structure | 74 | * ib_media_addr_set - initialize Infiniband media address structure |
@@ -120,20 +127,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, | |||
120 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | 127 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, |
121 | struct packet_type *pt, struct net_device *orig_dev) | 128 | struct packet_type *pt, struct net_device *orig_dev) |
122 | { | 129 | { |
123 | struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv; | 130 | struct tipc_bearer *b_ptr; |
124 | 131 | ||
125 | if (!net_eq(dev_net(dev), &init_net)) { | 132 | if (!net_eq(dev_net(dev), &init_net)) { |
126 | kfree_skb(buf); | 133 | kfree_skb(buf); |
127 | return NET_RX_DROP; | 134 | return NET_RX_DROP; |
128 | } | 135 | } |
129 | 136 | ||
130 | if (likely(ib_ptr->bearer)) { | 137 | rcu_read_lock(); |
138 | b_ptr = rcu_dereference(dev->tipc_ptr); | ||
139 | if (likely(b_ptr)) { | ||
131 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | 140 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { |
132 | buf->next = NULL; | 141 | buf->next = NULL; |
133 | tipc_recv_msg(buf, ib_ptr->bearer); | 142 | tipc_recv_msg(buf, b_ptr); |
143 | rcu_read_unlock(); | ||
134 | return NET_RX_SUCCESS; | 144 | return NET_RX_SUCCESS; |
135 | } | 145 | } |
136 | } | 146 | } |
147 | rcu_read_unlock(); | ||
148 | |||
137 | kfree_skb(buf); | 149 | kfree_skb(buf); |
138 | return NET_RX_DROP; | 150 | return NET_RX_DROP; |
139 | } | 151 | } |
@@ -143,10 +155,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, | |||
143 | */ | 155 | */ |
144 | static void setup_media(struct work_struct *work) | 156 | static void setup_media(struct work_struct *work) |
145 | { | 157 | { |
146 | struct ib_media *ib_ptr = | 158 | dev_add_pack(&tipc_packet_type); |
147 | container_of(work, struct ib_media, setup); | ||
148 | |||
149 | dev_add_pack(&ib_ptr->tipc_packet_type); | ||
150 | } | 159 | } |
151 | 160 | ||
152 | /** | 161 | /** |
@@ -175,15 +184,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) | |||
175 | 184 | ||
176 | /* Create InfiniBand bearer for device */ | 185 | /* Create InfiniBand bearer for device */ |
177 | ib_ptr->dev = dev; | 186 | ib_ptr->dev = dev; |
178 | ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); | ||
179 | ib_ptr->tipc_packet_type.dev = dev; | ||
180 | ib_ptr->tipc_packet_type.func = recv_msg; | ||
181 | ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr; | ||
182 | INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list)); | ||
183 | INIT_WORK(&ib_ptr->setup, setup_media); | 187 | INIT_WORK(&ib_ptr->setup, setup_media); |
184 | schedule_work(&ib_ptr->setup); | 188 | schedule_work(&ib_ptr->setup); |
185 | 189 | ||
186 | /* Associate TIPC bearer with InfiniBand bearer */ | 190 | /* Associate TIPC bearer with InfiniBand bearer */ |
191 | tb_ptr->dev = dev; | ||
187 | ib_ptr->bearer = tb_ptr; | 192 | ib_ptr->bearer = tb_ptr; |
188 | tb_ptr->usr_handle = (void *)ib_ptr; | 193 | tb_ptr->usr_handle = (void *)ib_ptr; |
189 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); | 194 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); |
@@ -192,6 +197,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) | |||
192 | tb_ptr->bcast_addr.broadcast = 1; | 197 | tb_ptr->bcast_addr.broadcast = 1; |
193 | tb_ptr->mtu = dev->mtu; | 198 | tb_ptr->mtu = dev->mtu; |
194 | ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); | 199 | ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); |
200 | rcu_assign_pointer(dev->tipc_ptr, tb_ptr); | ||
195 | return 0; | 201 | return 0; |
196 | } | 202 | } |
197 | 203 | ||
@@ -205,7 +211,7 @@ static void cleanup_bearer(struct work_struct *work) | |||
205 | struct ib_media *ib_ptr = | 211 | struct ib_media *ib_ptr = |
206 | container_of(work, struct ib_media, cleanup); | 212 | container_of(work, struct ib_media, cleanup); |
207 | 213 | ||
208 | dev_remove_pack(&ib_ptr->tipc_packet_type); | 214 | dev_remove_pack(&tipc_packet_type); |
209 | dev_put(ib_ptr->dev); | 215 | dev_put(ib_ptr->dev); |
210 | ib_ptr->dev = NULL; | 216 | ib_ptr->dev = NULL; |
211 | } | 217 | } |
@@ -224,6 +230,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) | |||
224 | ib_ptr->bearer = NULL; | 230 | ib_ptr->bearer = NULL; |
225 | INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); | 231 | INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); |
226 | schedule_work(&ib_ptr->cleanup); | 232 | schedule_work(&ib_ptr->cleanup); |
233 | RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); | ||
227 | } | 234 | } |
228 | 235 | ||
229 | /** | 236 | /** |
@@ -235,21 +242,20 @@ static void disable_media(struct tipc_bearer *tb_ptr) | |||
235 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | 242 | static int recv_notification(struct notifier_block *nb, unsigned long evt, |
236 | void *ptr) | 243 | void *ptr) |
237 | { | 244 | { |
245 | struct tipc_bearer *b_ptr; | ||
238 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 246 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
239 | struct ib_media *ib_ptr = &ib_media_array[0]; | ||
240 | struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; | ||
241 | 247 | ||
242 | if (!net_eq(dev_net(dev), &init_net)) | 248 | if (!net_eq(dev_net(dev), &init_net)) |
243 | return NOTIFY_DONE; | 249 | return NOTIFY_DONE; |
244 | 250 | ||
245 | while ((ib_ptr->dev != dev)) { | 251 | rcu_read_lock(); |
246 | if (++ib_ptr == stop) | 252 | b_ptr = rcu_dereference(dev->tipc_ptr); |
247 | return NOTIFY_DONE; /* couldn't find device */ | 253 | if (!b_ptr) { |
248 | } | 254 | rcu_read_unlock(); |
249 | if (!ib_ptr->bearer) | ||
250 | return NOTIFY_DONE; /* bearer had been disabled */ | 255 | return NOTIFY_DONE; /* bearer had been disabled */ |
256 | } | ||
251 | 257 | ||
252 | ib_ptr->bearer->mtu = dev->mtu; | 258 | b_ptr->mtu = dev->mtu; |
253 | 259 | ||
254 | switch (evt) { | 260 | switch (evt) { |
255 | case NETDEV_CHANGE: | 261 | case NETDEV_CHANGE: |
@@ -258,13 +264,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, | |||
258 | case NETDEV_DOWN: | 264 | case NETDEV_DOWN: |
259 | case NETDEV_CHANGEMTU: | 265 | case NETDEV_CHANGEMTU: |
260 | case NETDEV_CHANGEADDR: | 266 | case NETDEV_CHANGEADDR: |
261 | tipc_reset_bearer(ib_ptr->bearer); | 267 | tipc_reset_bearer(b_ptr); |
262 | break; | 268 | break; |
263 | case NETDEV_UNREGISTER: | 269 | case NETDEV_UNREGISTER: |
264 | case NETDEV_CHANGENAME: | 270 | case NETDEV_CHANGENAME: |
265 | tipc_disable_bearer(ib_ptr->bearer->name); | 271 | tipc_disable_bearer(b_ptr->name); |
266 | break; | 272 | break; |
267 | } | 273 | } |
274 | rcu_read_unlock(); | ||
275 | |||
268 | return NOTIFY_OK; | 276 | return NOTIFY_OK; |
269 | } | 277 | } |
270 | 278 | ||