aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/bearer.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/bearer.c')
-rw-r--r--net/tipc/bearer.c153
1 files changed, 70 insertions, 83 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 3fef7eb776dc..264474394f9f 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -49,7 +49,7 @@ static struct tipc_media * const media_info_array[] = {
49 NULL 49 NULL
50}; 50};
51 51
52struct tipc_bearer *bearer_list[MAX_BEARERS + 1]; 52struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
53 53
54static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down); 54static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
55 55
@@ -178,7 +178,7 @@ struct tipc_bearer *tipc_bearer_find(const char *name)
178 u32 i; 178 u32 i;
179 179
180 for (i = 0; i < MAX_BEARERS; i++) { 180 for (i = 0; i < MAX_BEARERS; i++) {
181 b_ptr = bearer_list[i]; 181 b_ptr = rtnl_dereference(bearer_list[i]);
182 if (b_ptr && (!strcmp(b_ptr->name, name))) 182 if (b_ptr && (!strcmp(b_ptr->name, name)))
183 return b_ptr; 183 return b_ptr;
184 } 184 }
@@ -198,10 +198,9 @@ struct sk_buff *tipc_bearer_get_names(void)
198 if (!buf) 198 if (!buf)
199 return NULL; 199 return NULL;
200 200
201 read_lock_bh(&tipc_net_lock);
202 for (i = 0; media_info_array[i] != NULL; i++) { 201 for (i = 0; media_info_array[i] != NULL; i++) {
203 for (j = 0; j < MAX_BEARERS; j++) { 202 for (j = 0; j < MAX_BEARERS; j++) {
204 b = bearer_list[j]; 203 b = rtnl_dereference(bearer_list[j]);
205 if (!b) 204 if (!b)
206 continue; 205 continue;
207 if (b->media == media_info_array[i]) { 206 if (b->media == media_info_array[i]) {
@@ -211,22 +210,33 @@ struct sk_buff *tipc_bearer_get_names(void)
211 } 210 }
212 } 211 }
213 } 212 }
214 read_unlock_bh(&tipc_net_lock);
215 return buf; 213 return buf;
216} 214}
217 215
218void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest) 216void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
219{ 217{
220 tipc_nmap_add(&b_ptr->nodes, dest); 218 struct tipc_bearer *b_ptr;
221 tipc_bcbearer_sort(); 219
222 tipc_disc_add_dest(b_ptr->link_req); 220 rcu_read_lock();
221 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
222 if (b_ptr) {
223 tipc_bcbearer_sort(&b_ptr->nodes, dest, true);
224 tipc_disc_add_dest(b_ptr->link_req);
225 }
226 rcu_read_unlock();
223} 227}
224 228
225void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest) 229void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
226{ 230{
227 tipc_nmap_remove(&b_ptr->nodes, dest); 231 struct tipc_bearer *b_ptr;
228 tipc_bcbearer_sort(); 232
229 tipc_disc_remove_dest(b_ptr->link_req); 233 rcu_read_lock();
234 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
235 if (b_ptr) {
236 tipc_bcbearer_sort(&b_ptr->nodes, dest, false);
237 tipc_disc_remove_dest(b_ptr->link_req);
238 }
239 rcu_read_unlock();
230} 240}
231 241
232/** 242/**
@@ -271,13 +281,11 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
271 return -EINVAL; 281 return -EINVAL;
272 } 282 }
273 283
274 write_lock_bh(&tipc_net_lock);
275
276 m_ptr = tipc_media_find(b_names.media_name); 284 m_ptr = tipc_media_find(b_names.media_name);
277 if (!m_ptr) { 285 if (!m_ptr) {
278 pr_warn("Bearer <%s> rejected, media <%s> not registered\n", 286 pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
279 name, b_names.media_name); 287 name, b_names.media_name);
280 goto exit; 288 return -EINVAL;
281 } 289 }
282 290
283 if (priority == TIPC_MEDIA_LINK_PRI) 291 if (priority == TIPC_MEDIA_LINK_PRI)
@@ -287,7 +295,7 @@ restart:
287 bearer_id = MAX_BEARERS; 295 bearer_id = MAX_BEARERS;
288 with_this_prio = 1; 296 with_this_prio = 1;
289 for (i = MAX_BEARERS; i-- != 0; ) { 297 for (i = MAX_BEARERS; i-- != 0; ) {
290 b_ptr = bearer_list[i]; 298 b_ptr = rtnl_dereference(bearer_list[i]);
291 if (!b_ptr) { 299 if (!b_ptr) {
292 bearer_id = i; 300 bearer_id = i;
293 continue; 301 continue;
@@ -295,14 +303,14 @@ restart:
295 if (!strcmp(name, b_ptr->name)) { 303 if (!strcmp(name, b_ptr->name)) {
296 pr_warn("Bearer <%s> rejected, already enabled\n", 304 pr_warn("Bearer <%s> rejected, already enabled\n",
297 name); 305 name);
298 goto exit; 306 return -EINVAL;
299 } 307 }
300 if ((b_ptr->priority == priority) && 308 if ((b_ptr->priority == priority) &&
301 (++with_this_prio > 2)) { 309 (++with_this_prio > 2)) {
302 if (priority-- == 0) { 310 if (priority-- == 0) {
303 pr_warn("Bearer <%s> rejected, duplicate priority\n", 311 pr_warn("Bearer <%s> rejected, duplicate priority\n",
304 name); 312 name);
305 goto exit; 313 return -EINVAL;
306 } 314 }
307 pr_warn("Bearer <%s> priority adjustment required %u->%u\n", 315 pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
308 name, priority + 1, priority); 316 name, priority + 1, priority);
@@ -312,21 +320,20 @@ restart:
312 if (bearer_id >= MAX_BEARERS) { 320 if (bearer_id >= MAX_BEARERS) {
313 pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n", 321 pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
314 name, MAX_BEARERS); 322 name, MAX_BEARERS);
315 goto exit; 323 return -EINVAL;
316 } 324 }
317 325
318 b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC); 326 b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
319 if (!b_ptr) { 327 if (!b_ptr)
320 res = -ENOMEM; 328 return -ENOMEM;
321 goto exit; 329
322 }
323 strcpy(b_ptr->name, name); 330 strcpy(b_ptr->name, name);
324 b_ptr->media = m_ptr; 331 b_ptr->media = m_ptr;
325 res = m_ptr->enable_media(b_ptr); 332 res = m_ptr->enable_media(b_ptr);
326 if (res) { 333 if (res) {
327 pr_warn("Bearer <%s> rejected, enable failure (%d)\n", 334 pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
328 name, -res); 335 name, -res);
329 goto exit; 336 return -EINVAL;
330 } 337 }
331 338
332 b_ptr->identity = bearer_id; 339 b_ptr->identity = bearer_id;
@@ -341,16 +348,14 @@ restart:
341 bearer_disable(b_ptr, false); 348 bearer_disable(b_ptr, false);
342 pr_warn("Bearer <%s> rejected, discovery object creation failed\n", 349 pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
343 name); 350 name);
344 goto exit; 351 return -EINVAL;
345 } 352 }
346 353
347 bearer_list[bearer_id] = b_ptr; 354 rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
348 355
349 pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n", 356 pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
350 name, 357 name,
351 tipc_addr_string_fill(addr_string, disc_domain), priority); 358 tipc_addr_string_fill(addr_string, disc_domain), priority);
352exit:
353 write_unlock_bh(&tipc_net_lock);
354 return res; 359 return res;
355} 360}
356 361
@@ -359,19 +364,16 @@ exit:
359 */ 364 */
360static int tipc_reset_bearer(struct tipc_bearer *b_ptr) 365static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
361{ 366{
362 read_lock_bh(&tipc_net_lock);
363 pr_info("Resetting bearer <%s>\n", b_ptr->name); 367 pr_info("Resetting bearer <%s>\n", b_ptr->name);
364 tipc_disc_delete(b_ptr->link_req);
365 tipc_link_reset_list(b_ptr->identity); 368 tipc_link_reset_list(b_ptr->identity);
366 tipc_disc_create(b_ptr, &b_ptr->bcast_addr); 369 tipc_disc_reset(b_ptr);
367 read_unlock_bh(&tipc_net_lock);
368 return 0; 370 return 0;
369} 371}
370 372
371/** 373/**
372 * bearer_disable 374 * bearer_disable
373 * 375 *
374 * Note: This routine assumes caller holds tipc_net_lock. 376 * Note: This routine assumes caller holds RTNL lock.
375 */ 377 */
376static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down) 378static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
377{ 379{
@@ -385,12 +387,12 @@ static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
385 tipc_disc_delete(b_ptr->link_req); 387 tipc_disc_delete(b_ptr->link_req);
386 388
387 for (i = 0; i < MAX_BEARERS; i++) { 389 for (i = 0; i < MAX_BEARERS; i++) {
388 if (b_ptr == bearer_list[i]) { 390 if (b_ptr == rtnl_dereference(bearer_list[i])) {
389 bearer_list[i] = NULL; 391 RCU_INIT_POINTER(bearer_list[i], NULL);
390 break; 392 break;
391 } 393 }
392 } 394 }
393 kfree(b_ptr); 395 kfree_rcu(b_ptr, rcu);
394} 396}
395 397
396int tipc_disable_bearer(const char *name) 398int tipc_disable_bearer(const char *name)
@@ -398,7 +400,6 @@ int tipc_disable_bearer(const char *name)
398 struct tipc_bearer *b_ptr; 400 struct tipc_bearer *b_ptr;
399 int res; 401 int res;
400 402
401 write_lock_bh(&tipc_net_lock);
402 b_ptr = tipc_bearer_find(name); 403 b_ptr = tipc_bearer_find(name);
403 if (b_ptr == NULL) { 404 if (b_ptr == NULL) {
404 pr_warn("Attempt to disable unknown bearer <%s>\n", name); 405 pr_warn("Attempt to disable unknown bearer <%s>\n", name);
@@ -407,32 +408,9 @@ int tipc_disable_bearer(const char *name)
407 bearer_disable(b_ptr, false); 408 bearer_disable(b_ptr, false);
408 res = 0; 409 res = 0;
409 } 410 }
410 write_unlock_bh(&tipc_net_lock);
411 return res; 411 return res;
412} 412}
413 413
414
415/* tipc_l2_media_addr_set - initialize Ethernet media address structure
416 *
417 * Media-dependent "value" field stores MAC address in first 6 bytes
418 * and zeroes out the remaining bytes.
419 */
420void tipc_l2_media_addr_set(const struct tipc_bearer *b,
421 struct tipc_media_addr *a, char *mac)
422{
423 int len = b->media->hwaddr_len;
424
425 if (unlikely(sizeof(a->value) < len)) {
426 WARN_ONCE(1, "Media length invalid\n");
427 return;
428 }
429
430 memcpy(a->value, mac, len);
431 memset(a->value + len, 0, sizeof(a->value) - len);
432 a->media_id = b->media->type_id;
433 a->broadcast = !memcmp(mac, b->bcast_addr.value, len);
434}
435
436int tipc_enable_l2_media(struct tipc_bearer *b) 414int tipc_enable_l2_media(struct tipc_bearer *b)
437{ 415{
438 struct net_device *dev; 416 struct net_device *dev;
@@ -443,33 +421,37 @@ int tipc_enable_l2_media(struct tipc_bearer *b)
443 if (!dev) 421 if (!dev)
444 return -ENODEV; 422 return -ENODEV;
445 423
446 /* Associate TIPC bearer with Ethernet bearer */ 424 /* Associate TIPC bearer with L2 bearer */
447 b->media_ptr = dev; 425 rcu_assign_pointer(b->media_ptr, dev);
448 memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value)); 426 memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));
449 memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len); 427 memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
450 b->bcast_addr.media_id = b->media->type_id; 428 b->bcast_addr.media_id = b->media->type_id;
451 b->bcast_addr.broadcast = 1; 429 b->bcast_addr.broadcast = 1;
452 b->mtu = dev->mtu; 430 b->mtu = dev->mtu;
453 tipc_l2_media_addr_set(b, &b->addr, (char *)dev->dev_addr); 431 b->media->raw2addr(b, &b->addr, (char *)dev->dev_addr);
454 rcu_assign_pointer(dev->tipc_ptr, b); 432 rcu_assign_pointer(dev->tipc_ptr, b);
455 return 0; 433 return 0;
456} 434}
457 435
458/* tipc_disable_l2_media - detach TIPC bearer from an Ethernet interface 436/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface
459 * 437 *
460 * Mark Ethernet bearer as inactive so that incoming buffers are thrown away, 438 * Mark L2 bearer as inactive so that incoming buffers are thrown away,
461 * then get worker thread to complete bearer cleanup. (Can't do cleanup 439 * then get worker thread to complete bearer cleanup. (Can't do cleanup
462 * here because cleanup code needs to sleep and caller holds spinlocks.) 440 * here because cleanup code needs to sleep and caller holds spinlocks.)
463 */ 441 */
464void tipc_disable_l2_media(struct tipc_bearer *b) 442void tipc_disable_l2_media(struct tipc_bearer *b)
465{ 443{
466 struct net_device *dev = (struct net_device *)b->media_ptr; 444 struct net_device *dev;
445
446 dev = (struct net_device *)rtnl_dereference(b->media_ptr);
447 RCU_INIT_POINTER(b->media_ptr, NULL);
467 RCU_INIT_POINTER(dev->tipc_ptr, NULL); 448 RCU_INIT_POINTER(dev->tipc_ptr, NULL);
449 synchronize_net();
468 dev_put(dev); 450 dev_put(dev);
469} 451}
470 452
471/** 453/**
472 * tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface 454 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
473 * @buf: the packet to be sent 455 * @buf: the packet to be sent
474 * @b_ptr: the bearer through which the packet is to be sent 456 * @b_ptr: the bearer through which the packet is to be sent
475 * @dest: peer destination address 457 * @dest: peer destination address
@@ -478,8 +460,12 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
478 struct tipc_media_addr *dest) 460 struct tipc_media_addr *dest)
479{ 461{
480 struct sk_buff *clone; 462 struct sk_buff *clone;
463 struct net_device *dev;
481 int delta; 464 int delta;
482 struct net_device *dev = (struct net_device *)b->media_ptr; 465
466 dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
467 if (!dev)
468 return 0;
483 469
484 clone = skb_clone(buf, GFP_ATOMIC); 470 clone = skb_clone(buf, GFP_ATOMIC);
485 if (!clone) 471 if (!clone)
@@ -507,10 +493,16 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
507 * The media send routine must not alter the buffer being passed in 493 * The media send routine must not alter the buffer being passed in
508 * as it may be needed for later retransmission! 494 * as it may be needed for later retransmission!
509 */ 495 */
510void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, 496void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
511 struct tipc_media_addr *dest) 497 struct tipc_media_addr *dest)
512{ 498{
513 b->media->send_msg(buf, b, dest); 499 struct tipc_bearer *b_ptr;
500
501 rcu_read_lock();
502 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
503 if (likely(b_ptr))
504 b_ptr->media->send_msg(buf, b_ptr, dest);
505 rcu_read_unlock();
514} 506}
515 507
516/** 508/**
@@ -535,7 +527,7 @@ static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
535 } 527 }
536 528
537 rcu_read_lock(); 529 rcu_read_lock();
538 b_ptr = rcu_dereference(dev->tipc_ptr); 530 b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
539 if (likely(b_ptr)) { 531 if (likely(b_ptr)) {
540 if (likely(buf->pkt_type <= PACKET_BROADCAST)) { 532 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
541 buf->next = NULL; 533 buf->next = NULL;
@@ -568,12 +560,9 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
568 if (!net_eq(dev_net(dev), &init_net)) 560 if (!net_eq(dev_net(dev), &init_net))
569 return NOTIFY_DONE; 561 return NOTIFY_DONE;
570 562
571 rcu_read_lock(); 563 b_ptr = rtnl_dereference(dev->tipc_ptr);
572 b_ptr = rcu_dereference(dev->tipc_ptr); 564 if (!b_ptr)
573 if (!b_ptr) {
574 rcu_read_unlock();
575 return NOTIFY_DONE; 565 return NOTIFY_DONE;
576 }
577 566
578 b_ptr->mtu = dev->mtu; 567 b_ptr->mtu = dev->mtu;
579 568
@@ -586,17 +575,15 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
586 tipc_reset_bearer(b_ptr); 575 tipc_reset_bearer(b_ptr);
587 break; 576 break;
588 case NETDEV_CHANGEADDR: 577 case NETDEV_CHANGEADDR:
589 tipc_l2_media_addr_set(b_ptr, &b_ptr->addr, 578 b_ptr->media->raw2addr(b_ptr, &b_ptr->addr,
590 (char *)dev->dev_addr); 579 (char *)dev->dev_addr);
591 tipc_reset_bearer(b_ptr); 580 tipc_reset_bearer(b_ptr);
592 break; 581 break;
593 case NETDEV_UNREGISTER: 582 case NETDEV_UNREGISTER:
594 case NETDEV_CHANGENAME: 583 case NETDEV_CHANGENAME:
595 tipc_disable_bearer(b_ptr->name); 584 bearer_disable(b_ptr, false);
596 break; 585 break;
597 } 586 }
598 rcu_read_unlock();
599
600 return NOTIFY_OK; 587 return NOTIFY_OK;
601} 588}
602 589
@@ -633,7 +620,7 @@ void tipc_bearer_stop(void)
633 u32 i; 620 u32 i;
634 621
635 for (i = 0; i < MAX_BEARERS; i++) { 622 for (i = 0; i < MAX_BEARERS; i++) {
636 b_ptr = bearer_list[i]; 623 b_ptr = rtnl_dereference(bearer_list[i]);
637 if (b_ptr) { 624 if (b_ptr) {
638 bearer_disable(b_ptr, true); 625 bearer_disable(b_ptr, true);
639 bearer_list[i] = NULL; 626 bearer_list[i] = NULL;