diff options
Diffstat (limited to 'net/tipc/bearer.c')
| -rw-r--r-- | net/tipc/bearer.c | 347 |
1 files changed, 240 insertions, 107 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 3f9707a16d06..574b86193b15 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bearer.c: TIPC bearer code | 2 | * net/tipc/bearer.c: TIPC bearer code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1996-2006, Ericsson AB | 4 | * Copyright (c) 1996-2006, 2013, Ericsson AB |
| 5 | * Copyright (c) 2004-2006, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2004-2006, 2010-2013, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
| @@ -41,8 +41,13 @@ | |||
| 41 | 41 | ||
| 42 | #define MAX_ADDR_STR 60 | 42 | #define MAX_ADDR_STR 60 |
| 43 | 43 | ||
| 44 | static struct tipc_media *media_list[MAX_MEDIA]; | 44 | static struct tipc_media * const media_info_array[] = { |
| 45 | static u32 media_count; | 45 | ð_media_info, |
| 46 | #ifdef CONFIG_TIPC_MEDIA_IB | ||
| 47 | &ib_media_info, | ||
| 48 | #endif | ||
| 49 | NULL | ||
| 50 | }; | ||
| 46 | 51 | ||
| 47 | struct tipc_bearer tipc_bearers[MAX_BEARERS]; | 52 | struct tipc_bearer tipc_bearers[MAX_BEARERS]; |
| 48 | 53 | ||
| @@ -55,11 +60,11 @@ struct tipc_media *tipc_media_find(const char *name) | |||
| 55 | { | 60 | { |
| 56 | u32 i; | 61 | u32 i; |
| 57 | 62 | ||
| 58 | for (i = 0; i < media_count; i++) { | 63 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 59 | if (!strcmp(media_list[i]->name, name)) | 64 | if (!strcmp(media_info_array[i]->name, name)) |
| 60 | return media_list[i]; | 65 | break; |
| 61 | } | 66 | } |
| 62 | return NULL; | 67 | return media_info_array[i]; |
| 63 | } | 68 | } |
| 64 | 69 | ||
| 65 | /** | 70 | /** |
| @@ -69,44 +74,11 @@ static struct tipc_media *media_find_id(u8 type) | |||
| 69 | { | 74 | { |
| 70 | u32 i; | 75 | u32 i; |
| 71 | 76 | ||
| 72 | for (i = 0; i < media_count; i++) { | 77 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 73 | if (media_list[i]->type_id == type) | 78 | if (media_info_array[i]->type_id == type) |
| 74 | return media_list[i]; | 79 | break; |
| 75 | } | 80 | } |
| 76 | return NULL; | 81 | return media_info_array[i]; |
| 77 | } | ||
| 78 | |||
| 79 | /** | ||
| 80 | * tipc_register_media - register a media type | ||
| 81 | * | ||
| 82 | * Bearers for this media type must be activated separately at a later stage. | ||
| 83 | */ | ||
| 84 | int tipc_register_media(struct tipc_media *m_ptr) | ||
| 85 | { | ||
| 86 | int res = -EINVAL; | ||
| 87 | |||
| 88 | write_lock_bh(&tipc_net_lock); | ||
| 89 | |||
| 90 | if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME) | ||
| 91 | goto exit; | ||
| 92 | if (m_ptr->priority > TIPC_MAX_LINK_PRI) | ||
| 93 | goto exit; | ||
| 94 | if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) || | ||
| 95 | (m_ptr->tolerance > TIPC_MAX_LINK_TOL)) | ||
| 96 | goto exit; | ||
| 97 | if (media_count >= MAX_MEDIA) | ||
| 98 | goto exit; | ||
| 99 | if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id)) | ||
| 100 | goto exit; | ||
| 101 | |||
| 102 | media_list[media_count] = m_ptr; | ||
| 103 | media_count++; | ||
| 104 | res = 0; | ||
| 105 | exit: | ||
| 106 | write_unlock_bh(&tipc_net_lock); | ||
| 107 | if (res) | ||
| 108 | pr_warn("Media <%s> registration error\n", m_ptr->name); | ||
| 109 | return res; | ||
| 110 | } | 82 | } |
| 111 | 83 | ||
| 112 | /** | 84 | /** |
| @@ -144,13 +116,11 @@ struct sk_buff *tipc_media_get_names(void) | |||
| 144 | if (!buf) | 116 | if (!buf) |
| 145 | return NULL; | 117 | return NULL; |
| 146 | 118 | ||
| 147 | read_lock_bh(&tipc_net_lock); | 119 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 148 | for (i = 0; i < media_count; i++) { | ||
| 149 | tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, | 120 | tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, |
| 150 | media_list[i]->name, | 121 | media_info_array[i]->name, |
| 151 | strlen(media_list[i]->name) + 1); | 122 | strlen(media_info_array[i]->name) + 1); |
| 152 | } | 123 | } |
| 153 | read_unlock_bh(&tipc_net_lock); | ||
| 154 | return buf; | 124 | return buf; |
| 155 | } | 125 | } |
| 156 | 126 | ||
| @@ -215,31 +185,12 @@ struct tipc_bearer *tipc_bearer_find(const char *name) | |||
| 215 | } | 185 | } |
| 216 | 186 | ||
| 217 | /** | 187 | /** |
| 218 | * tipc_bearer_find_interface - locates bearer object with matching interface name | ||
| 219 | */ | ||
| 220 | struct tipc_bearer *tipc_bearer_find_interface(const char *if_name) | ||
| 221 | { | ||
| 222 | struct tipc_bearer *b_ptr; | ||
| 223 | char *b_if_name; | ||
| 224 | u32 i; | ||
| 225 | |||
| 226 | for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) { | ||
| 227 | if (!b_ptr->active) | ||
| 228 | continue; | ||
| 229 | b_if_name = strchr(b_ptr->name, ':') + 1; | ||
| 230 | if (!strcmp(b_if_name, if_name)) | ||
| 231 | return b_ptr; | ||
| 232 | } | ||
| 233 | return NULL; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * tipc_bearer_get_names - record names of bearers in buffer | 188 | * tipc_bearer_get_names - record names of bearers in buffer |
| 238 | */ | 189 | */ |
| 239 | struct sk_buff *tipc_bearer_get_names(void) | 190 | struct sk_buff *tipc_bearer_get_names(void) |
| 240 | { | 191 | { |
| 241 | struct sk_buff *buf; | 192 | struct sk_buff *buf; |
| 242 | struct tipc_bearer *b_ptr; | 193 | struct tipc_bearer *b; |
| 243 | int i, j; | 194 | int i, j; |
| 244 | 195 | ||
| 245 | buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME)); | 196 | buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME)); |
| @@ -247,13 +198,13 @@ struct sk_buff *tipc_bearer_get_names(void) | |||
| 247 | return NULL; | 198 | return NULL; |
| 248 | 199 | ||
| 249 | read_lock_bh(&tipc_net_lock); | 200 | read_lock_bh(&tipc_net_lock); |
| 250 | for (i = 0; i < media_count; i++) { | 201 | for (i = 0; media_info_array[i] != NULL; i++) { |
| 251 | for (j = 0; j < MAX_BEARERS; j++) { | 202 | for (j = 0; j < MAX_BEARERS; j++) { |
| 252 | b_ptr = &tipc_bearers[j]; | 203 | b = &tipc_bearers[j]; |
| 253 | if (b_ptr->active && (b_ptr->media == media_list[i])) { | 204 | if (b->active && (b->media == media_info_array[i])) { |
| 254 | tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, | 205 | tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, |
| 255 | b_ptr->name, | 206 | b->name, |
| 256 | strlen(b_ptr->name) + 1); | 207 | strlen(b->name) + 1); |
| 257 | } | 208 | } |
| 258 | } | 209 | } |
| 259 | } | 210 | } |
| @@ -275,31 +226,6 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest) | |||
| 275 | tipc_disc_remove_dest(b_ptr->link_req); | 226 | tipc_disc_remove_dest(b_ptr->link_req); |
| 276 | } | 227 | } |
| 277 | 228 | ||
| 278 | /* | ||
| 279 | * Interrupt enabling new requests after bearer blocking: | ||
| 280 | * See bearer_send(). | ||
| 281 | */ | ||
| 282 | void tipc_continue(struct tipc_bearer *b) | ||
| 283 | { | ||
| 284 | spin_lock_bh(&b->lock); | ||
| 285 | b->blocked = 0; | ||
| 286 | spin_unlock_bh(&b->lock); | ||
| 287 | } | ||
| 288 | |||
| 289 | /* | ||
| 290 | * tipc_bearer_blocked - determines if bearer is currently blocked | ||
| 291 | */ | ||
| 292 | int tipc_bearer_blocked(struct tipc_bearer *b) | ||
| 293 | { | ||
| 294 | int res; | ||
| 295 | |||
| 296 | spin_lock_bh(&b->lock); | ||
| 297 | res = b->blocked; | ||
| 298 | spin_unlock_bh(&b->lock); | ||
| 299 | |||
| 300 | return res; | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | 229 | /** |
| 304 | * tipc_enable_bearer - enable bearer with the given name | 230 | * tipc_enable_bearer - enable bearer with the given name |
| 305 | */ | 231 | */ |
| @@ -387,6 +313,7 @@ restart: | |||
| 387 | 313 | ||
| 388 | b_ptr = &tipc_bearers[bearer_id]; | 314 | b_ptr = &tipc_bearers[bearer_id]; |
| 389 | strcpy(b_ptr->name, name); | 315 | strcpy(b_ptr->name, name); |
| 316 | b_ptr->media = m_ptr; | ||
| 390 | res = m_ptr->enable_media(b_ptr); | 317 | res = m_ptr->enable_media(b_ptr); |
| 391 | if (res) { | 318 | if (res) { |
| 392 | pr_warn("Bearer <%s> rejected, enable failure (%d)\n", | 319 | pr_warn("Bearer <%s> rejected, enable failure (%d)\n", |
| @@ -395,7 +322,6 @@ restart: | |||
| 395 | } | 322 | } |
| 396 | 323 | ||
| 397 | b_ptr->identity = bearer_id; | 324 | b_ptr->identity = bearer_id; |
| 398 | b_ptr->media = m_ptr; | ||
| 399 | b_ptr->tolerance = m_ptr->tolerance; | 325 | b_ptr->tolerance = m_ptr->tolerance; |
| 400 | b_ptr->window = m_ptr->window; | 326 | b_ptr->window = m_ptr->window; |
| 401 | b_ptr->net_plane = bearer_id + 'A'; | 327 | b_ptr->net_plane = bearer_id + 'A'; |
| @@ -420,17 +346,16 @@ exit: | |||
| 420 | } | 346 | } |
| 421 | 347 | ||
| 422 | /** | 348 | /** |
| 423 | * tipc_block_bearer - Block the bearer, and reset all its links | 349 | * tipc_reset_bearer - Reset all links established over this bearer |
| 424 | */ | 350 | */ |
| 425 | int tipc_block_bearer(struct tipc_bearer *b_ptr) | 351 | static int tipc_reset_bearer(struct tipc_bearer *b_ptr) |
| 426 | { | 352 | { |
| 427 | struct tipc_link *l_ptr; | 353 | struct tipc_link *l_ptr; |
| 428 | struct tipc_link *temp_l_ptr; | 354 | struct tipc_link *temp_l_ptr; |
| 429 | 355 | ||
| 430 | read_lock_bh(&tipc_net_lock); | 356 | read_lock_bh(&tipc_net_lock); |
| 431 | pr_info("Blocking bearer <%s>\n", b_ptr->name); | 357 | pr_info("Resetting bearer <%s>\n", b_ptr->name); |
| 432 | spin_lock_bh(&b_ptr->lock); | 358 | spin_lock_bh(&b_ptr->lock); |
| 433 | b_ptr->blocked = 1; | ||
| 434 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { | 359 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { |
| 435 | struct tipc_node *n_ptr = l_ptr->owner; | 360 | struct tipc_node *n_ptr = l_ptr->owner; |
| 436 | 361 | ||
| @@ -456,7 +381,6 @@ static void bearer_disable(struct tipc_bearer *b_ptr) | |||
| 456 | 381 | ||
| 457 | pr_info("Disabling bearer <%s>\n", b_ptr->name); | 382 | pr_info("Disabling bearer <%s>\n", b_ptr->name); |
| 458 | spin_lock_bh(&b_ptr->lock); | 383 | spin_lock_bh(&b_ptr->lock); |
| 459 | b_ptr->blocked = 1; | ||
| 460 | b_ptr->media->disable_media(b_ptr); | 384 | b_ptr->media->disable_media(b_ptr); |
| 461 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { | 385 | list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { |
| 462 | tipc_link_delete(l_ptr); | 386 | tipc_link_delete(l_ptr); |
| @@ -490,6 +414,216 @@ int tipc_disable_bearer(const char *name) | |||
| 490 | } | 414 | } |
| 491 | 415 | ||
| 492 | 416 | ||
| 417 | /* tipc_l2_media_addr_set - initialize Ethernet media address structure | ||
| 418 | * | ||
| 419 | * Media-dependent "value" field stores MAC address in first 6 bytes | ||
| 420 | * and zeroes out the remaining bytes. | ||
| 421 | */ | ||
| 422 | void tipc_l2_media_addr_set(const struct tipc_bearer *b, | ||
| 423 | struct tipc_media_addr *a, char *mac) | ||
| 424 | { | ||
| 425 | int len = b->media->hwaddr_len; | ||
| 426 | |||
| 427 | if (unlikely(sizeof(a->value) < len)) { | ||
| 428 | WARN_ONCE(1, "Media length invalid\n"); | ||
| 429 | return; | ||
| 430 | } | ||
| 431 | |||
| 432 | memcpy(a->value, mac, len); | ||
| 433 | memset(a->value + len, 0, sizeof(a->value) - len); | ||
| 434 | a->media_id = b->media->type_id; | ||
| 435 | a->broadcast = !memcmp(mac, b->bcast_addr.value, len); | ||
| 436 | } | ||
| 437 | |||
| 438 | int tipc_enable_l2_media(struct tipc_bearer *b) | ||
| 439 | { | ||
| 440 | struct net_device *dev; | ||
| 441 | char *driver_name = strchr((const char *)b->name, ':') + 1; | ||
| 442 | |||
| 443 | /* Find device with specified name */ | ||
| 444 | dev = dev_get_by_name(&init_net, driver_name); | ||
| 445 | if (!dev) | ||
| 446 | return -ENODEV; | ||
| 447 | |||
| 448 | /* Associate TIPC bearer with Ethernet bearer */ | ||
| 449 | b->media_ptr = dev; | ||
| 450 | memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value)); | ||
| 451 | memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len); | ||
| 452 | b->bcast_addr.media_id = b->media->type_id; | ||
| 453 | b->bcast_addr.broadcast = 1; | ||
| 454 | b->mtu = dev->mtu; | ||
| 455 | tipc_l2_media_addr_set(b, &b->addr, (char *)dev->dev_addr); | ||
| 456 | rcu_assign_pointer(dev->tipc_ptr, b); | ||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | |||
| 460 | /* tipc_disable_l2_media - detach TIPC bearer from an Ethernet interface | ||
| 461 | * | ||
| 462 | * Mark Ethernet bearer as inactive so that incoming buffers are thrown away, | ||
| 463 | * then get worker thread to complete bearer cleanup. (Can't do cleanup | ||
| 464 | * here because cleanup code needs to sleep and caller holds spinlocks.) | ||
| 465 | */ | ||
| 466 | void tipc_disable_l2_media(struct tipc_bearer *b) | ||
| 467 | { | ||
| 468 | struct net_device *dev = (struct net_device *)b->media_ptr; | ||
| 469 | RCU_INIT_POINTER(dev->tipc_ptr, NULL); | ||
| 470 | dev_put(dev); | ||
| 471 | } | ||
| 472 | |||
| 473 | /** | ||
| 474 | * tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface | ||
| 475 | * @buf: the packet to be sent | ||
| 476 | * @b_ptr: the bearer through which the packet is to be sent | ||
| 477 | * @dest: peer destination address | ||
| 478 | */ | ||
| 479 | int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, | ||
| 480 | struct tipc_media_addr *dest) | ||
| 481 | { | ||
| 482 | struct sk_buff *clone; | ||
| 483 | int delta; | ||
| 484 | struct net_device *dev = (struct net_device *)b->media_ptr; | ||
| 485 | |||
| 486 | clone = skb_clone(buf, GFP_ATOMIC); | ||
| 487 | if (!clone) | ||
| 488 | return 0; | ||
| 489 | |||
| 490 | delta = dev->hard_header_len - skb_headroom(buf); | ||
| 491 | if ((delta > 0) && | ||
| 492 | pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { | ||
| 493 | kfree_skb(clone); | ||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | skb_reset_network_header(clone); | ||
| 498 | clone->dev = dev; | ||
| 499 | clone->protocol = htons(ETH_P_TIPC); | ||
| 500 | dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, | ||
| 501 | dev->dev_addr, clone->len); | ||
| 502 | dev_queue_xmit(clone); | ||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* tipc_bearer_send- sends buffer to destination over bearer | ||
| 507 | * | ||
| 508 | * IMPORTANT: | ||
| 509 | * The media send routine must not alter the buffer being passed in | ||
| 510 | * as it may be needed for later retransmission! | ||
| 511 | */ | ||
| 512 | void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, | ||
| 513 | struct tipc_media_addr *dest) | ||
| 514 | { | ||
| 515 | b->media->send_msg(buf, b, dest); | ||
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | * tipc_l2_rcv_msg - handle incoming TIPC message from an interface | ||
| 520 | * @buf: the received packet | ||
| 521 | * @dev: the net device that the packet was received on | ||
| 522 | * @pt: the packet_type structure which was used to register this handler | ||
| 523 | * @orig_dev: the original receive net device in case the device is a bond | ||
| 524 | * | ||
| 525 | * Accept only packets explicitly sent to this node, or broadcast packets; | ||
| 526 | * ignores packets sent using interface multicast, and traffic sent to other | ||
| 527 | * nodes (which can happen if interface is running in promiscuous mode). | ||
| 528 | */ | ||
| 529 | static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev, | ||
| 530 | struct packet_type *pt, struct net_device *orig_dev) | ||
| 531 | { | ||
| 532 | struct tipc_bearer *b_ptr; | ||
| 533 | |||
| 534 | if (!net_eq(dev_net(dev), &init_net)) { | ||
| 535 | kfree_skb(buf); | ||
| 536 | return NET_RX_DROP; | ||
| 537 | } | ||
| 538 | |||
| 539 | rcu_read_lock(); | ||
| 540 | b_ptr = rcu_dereference(dev->tipc_ptr); | ||
| 541 | if (likely(b_ptr)) { | ||
| 542 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | ||
| 543 | buf->next = NULL; | ||
| 544 | tipc_rcv(buf, b_ptr); | ||
| 545 | rcu_read_unlock(); | ||
| 546 | return NET_RX_SUCCESS; | ||
| 547 | } | ||
| 548 | } | ||
| 549 | rcu_read_unlock(); | ||
| 550 | |||
| 551 | kfree_skb(buf); | ||
| 552 | return NET_RX_DROP; | ||
| 553 | } | ||
| 554 | |||
| 555 | /** | ||
| 556 | * tipc_l2_device_event - handle device events from network device | ||
| 557 | * @nb: the context of the notification | ||
| 558 | * @evt: the type of event | ||
| 559 | * @ptr: the net device that the event was on | ||
| 560 | * | ||
| 561 | * This function is called by the Ethernet driver in case of link | ||
| 562 | * change event. | ||
| 563 | */ | ||
| 564 | static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, | ||
| 565 | void *ptr) | ||
| 566 | { | ||
| 567 | struct tipc_bearer *b_ptr; | ||
| 568 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 569 | |||
| 570 | if (!net_eq(dev_net(dev), &init_net)) | ||
| 571 | return NOTIFY_DONE; | ||
| 572 | |||
| 573 | rcu_read_lock(); | ||
| 574 | b_ptr = rcu_dereference(dev->tipc_ptr); | ||
| 575 | if (!b_ptr) { | ||
| 576 | rcu_read_unlock(); | ||
| 577 | return NOTIFY_DONE; | ||
| 578 | } | ||
| 579 | |||
| 580 | b_ptr->mtu = dev->mtu; | ||
| 581 | |||
| 582 | switch (evt) { | ||
| 583 | case NETDEV_CHANGE: | ||
| 584 | if (netif_carrier_ok(dev)) | ||
| 585 | break; | ||
| 586 | case NETDEV_DOWN: | ||
| 587 | case NETDEV_CHANGEMTU: | ||
| 588 | case NETDEV_CHANGEADDR: | ||
| 589 | tipc_reset_bearer(b_ptr); | ||
| 590 | break; | ||
| 591 | case NETDEV_UNREGISTER: | ||
| 592 | case NETDEV_CHANGENAME: | ||
| 593 | tipc_disable_bearer(b_ptr->name); | ||
| 594 | break; | ||
| 595 | } | ||
| 596 | rcu_read_unlock(); | ||
| 597 | |||
| 598 | return NOTIFY_OK; | ||
| 599 | } | ||
| 600 | |||
| 601 | static struct packet_type tipc_packet_type __read_mostly = { | ||
| 602 | .type = __constant_htons(ETH_P_TIPC), | ||
| 603 | .func = tipc_l2_rcv_msg, | ||
| 604 | }; | ||
| 605 | |||
| 606 | static struct notifier_block notifier = { | ||
| 607 | .notifier_call = tipc_l2_device_event, | ||
| 608 | .priority = 0, | ||
| 609 | }; | ||
| 610 | |||
| 611 | int tipc_bearer_setup(void) | ||
| 612 | { | ||
| 613 | int err; | ||
| 614 | |||
| 615 | err = register_netdevice_notifier(¬ifier); | ||
| 616 | if (err) | ||
| 617 | return err; | ||
| 618 | dev_add_pack(&tipc_packet_type); | ||
| 619 | return 0; | ||
| 620 | } | ||
| 621 | |||
| 622 | void tipc_bearer_cleanup(void) | ||
| 623 | { | ||
| 624 | unregister_netdevice_notifier(¬ifier); | ||
| 625 | dev_remove_pack(&tipc_packet_type); | ||
| 626 | } | ||
| 493 | 627 | ||
| 494 | void tipc_bearer_stop(void) | 628 | void tipc_bearer_stop(void) |
| 495 | { | 629 | { |
| @@ -499,5 +633,4 @@ void tipc_bearer_stop(void) | |||
| 499 | if (tipc_bearers[i].active) | 633 | if (tipc_bearers[i].active) |
| 500 | bearer_disable(&tipc_bearers[i]); | 634 | bearer_disable(&tipc_bearers[i]); |
| 501 | } | 635 | } |
| 502 | media_count = 0; | ||
| 503 | } | 636 | } |
