diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/bcast.c | 8 | ||||
| -rw-r--r-- | net/tipc/bearer.c | 347 | ||||
| -rw-r--r-- | net/tipc/bearer.h | 56 | ||||
| -rw-r--r-- | net/tipc/config.c | 11 | ||||
| -rw-r--r-- | net/tipc/core.c | 113 | ||||
| -rw-r--r-- | net/tipc/core.h | 4 | ||||
| -rw-r--r-- | net/tipc/discover.c | 28 | ||||
| -rw-r--r-- | net/tipc/eth_media.c | 326 | ||||
| -rw-r--r-- | net/tipc/handler.c | 1 | ||||
| -rw-r--r-- | net/tipc/ib_media.c | 319 | ||||
| -rw-r--r-- | net/tipc/link.c | 230 | ||||
| -rw-r--r-- | net/tipc/link.h | 25 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 43 | ||||
| -rw-r--r-- | net/tipc/netlink.c | 8 | ||||
| -rw-r--r-- | net/tipc/node.c | 15 | ||||
| -rw-r--r-- | net/tipc/node.h | 3 | ||||
| -rw-r--r-- | net/tipc/port.c | 9 | ||||
| -rw-r--r-- | net/tipc/ref.c | 3 | ||||
| -rw-r--r-- | net/tipc/server.c | 21 | ||||
| -rw-r--r-- | net/tipc/server.h | 2 | ||||
| -rw-r--r-- | net/tipc/socket.c | 338 | ||||
| -rw-r--r-- | net/tipc/subscr.c | 50 |
22 files changed, 739 insertions, 1221 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 0d4402587fdf..bf860d9e75af 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -621,12 +621,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 621 | if (!p) | 621 | if (!p) |
| 622 | break; /* No more bearers to try */ | 622 | break; /* No more bearers to try */ |
| 623 | 623 | ||
| 624 | if (tipc_bearer_blocked(p)) { | ||
| 625 | if (!s || tipc_bearer_blocked(s)) | ||
| 626 | continue; /* Can't use either bearer */ | ||
| 627 | b = s; | ||
| 628 | } | ||
| 629 | |||
| 630 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, | 624 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, |
| 631 | &bcbearer->remains_new); | 625 | &bcbearer->remains_new); |
| 632 | if (bcbearer->remains_new.count == bcbearer->remains.count) | 626 | if (bcbearer->remains_new.count == bcbearer->remains.count) |
| @@ -800,7 +794,7 @@ void tipc_bclink_init(void) | |||
| 800 | void tipc_bclink_stop(void) | 794 | void tipc_bclink_stop(void) |
| 801 | { | 795 | { |
| 802 | spin_lock_bh(&bc_lock); | 796 | spin_lock_bh(&bc_lock); |
| 803 | tipc_link_stop(bcl); | 797 | tipc_link_purge_queues(bcl); |
| 804 | spin_unlock_bh(&bc_lock); | 798 | spin_unlock_bh(&bc_lock); |
| 805 | 799 | ||
| 806 | memset(bclink, 0, sizeof(*bclink)); | 800 | memset(bclink, 0, sizeof(*bclink)); |
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 | } |
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index e5e04be6fffa..4f5db9ad5bf6 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bearer.h: Include file for TIPC bearer code | 2 | * net/tipc/bearer.h: Include file for TIPC bearer code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1996-2006, Ericsson AB | 4 | * Copyright (c) 1996-2006, 2013, Ericsson AB |
| 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -73,18 +73,18 @@ struct tipc_media_addr { | |||
| 73 | struct tipc_bearer; | 73 | struct tipc_bearer; |
| 74 | 74 | ||
| 75 | /** | 75 | /** |
| 76 | * struct tipc_media - TIPC media information available to internal users | 76 | * struct tipc_media - Media specific info exposed to generic bearer layer |
| 77 | * @send_msg: routine which handles buffer transmission | 77 | * @send_msg: routine which handles buffer transmission |
| 78 | * @enable_media: routine which enables a media | 78 | * @enable_media: routine which enables a media |
| 79 | * @disable_media: routine which disables a media | 79 | * @disable_media: routine which disables a media |
| 80 | * @addr2str: routine which converts media address to string | 80 | * @addr2str: routine which converts media address to string |
| 81 | * @addr2msg: routine which converts media address to protocol message area | 81 | * @addr2msg: routine which converts media address to protocol message area |
| 82 | * @msg2addr: routine which converts media address from protocol message area | 82 | * @msg2addr: routine which converts media address from protocol message area |
| 83 | * @bcast_addr: media address used in broadcasting | ||
| 84 | * @priority: default link (and bearer) priority | 83 | * @priority: default link (and bearer) priority |
| 85 | * @tolerance: default time (in ms) before declaring link failure | 84 | * @tolerance: default time (in ms) before declaring link failure |
| 86 | * @window: default window (in packets) before declaring link congestion | 85 | * @window: default window (in packets) before declaring link congestion |
| 87 | * @type_id: TIPC media identifier | 86 | * @type_id: TIPC media identifier |
| 87 | * @hwaddr_len: TIPC media address len | ||
| 88 | * @name: media name | 88 | * @name: media name |
| 89 | */ | 89 | */ |
| 90 | struct tipc_media { | 90 | struct tipc_media { |
| @@ -101,18 +101,20 @@ struct tipc_media { | |||
| 101 | u32 tolerance; | 101 | u32 tolerance; |
| 102 | u32 window; | 102 | u32 window; |
| 103 | u32 type_id; | 103 | u32 type_id; |
| 104 | u32 hwaddr_len; | ||
| 104 | char name[TIPC_MAX_MEDIA_NAME]; | 105 | char name[TIPC_MAX_MEDIA_NAME]; |
| 105 | }; | 106 | }; |
| 106 | 107 | ||
| 107 | /** | 108 | /** |
| 108 | * struct tipc_bearer - TIPC bearer structure | 109 | * struct tipc_bearer - Generic TIPC bearer structure |
| 110 | * @dev: ptr to associated network device | ||
| 109 | * @usr_handle: pointer to additional media-specific information about bearer | 111 | * @usr_handle: pointer to additional media-specific information about bearer |
| 110 | * @mtu: max packet size bearer can support | 112 | * @mtu: max packet size bearer can support |
| 111 | * @blocked: non-zero if bearer is blocked | ||
| 112 | * @lock: spinlock for controlling access to bearer | 113 | * @lock: spinlock for controlling access to bearer |
| 113 | * @addr: media-specific address associated with bearer | 114 | * @addr: media-specific address associated with bearer |
| 114 | * @name: bearer name (format = media:interface) | 115 | * @name: bearer name (format = media:interface) |
| 115 | * @media: ptr to media structure associated with bearer | 116 | * @media: ptr to media structure associated with bearer |
| 117 | * @bcast_addr: media address used in broadcasting | ||
| 116 | * @priority: default link priority for bearer | 118 | * @priority: default link priority for bearer |
| 117 | * @window: default window size for bearer | 119 | * @window: default window size for bearer |
| 118 | * @tolerance: default link tolerance for bearer | 120 | * @tolerance: default link tolerance for bearer |
| @@ -128,9 +130,8 @@ struct tipc_media { | |||
| 128 | * care of initializing all other fields. | 130 | * care of initializing all other fields. |
| 129 | */ | 131 | */ |
| 130 | struct tipc_bearer { | 132 | struct tipc_bearer { |
| 131 | void *usr_handle; /* initalized by media */ | 133 | void *media_ptr; /* initalized by media */ |
| 132 | u32 mtu; /* initalized by media */ | 134 | u32 mtu; /* initalized by media */ |
| 133 | int blocked; /* initalized by media */ | ||
| 134 | struct tipc_media_addr addr; /* initalized by media */ | 135 | struct tipc_media_addr addr; /* initalized by media */ |
| 135 | char name[TIPC_MAX_BEARER_NAME]; | 136 | char name[TIPC_MAX_BEARER_NAME]; |
| 136 | spinlock_t lock; | 137 | spinlock_t lock; |
| @@ -159,55 +160,40 @@ extern struct tipc_bearer tipc_bearers[]; | |||
| 159 | /* | 160 | /* |
| 160 | * TIPC routines available to supported media types | 161 | * TIPC routines available to supported media types |
| 161 | */ | 162 | */ |
| 162 | int tipc_register_media(struct tipc_media *m_ptr); | ||
| 163 | |||
| 164 | void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); | ||
| 165 | |||
| 166 | int tipc_block_bearer(struct tipc_bearer *b_ptr); | ||
| 167 | void tipc_continue(struct tipc_bearer *tb_ptr); | ||
| 168 | 163 | ||
| 164 | void tipc_rcv(struct sk_buff *buf, struct tipc_bearer *tb_ptr); | ||
| 169 | int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority); | 165 | int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority); |
| 170 | int tipc_disable_bearer(const char *name); | 166 | int tipc_disable_bearer(const char *name); |
| 171 | 167 | ||
| 172 | /* | 168 | /* |
| 173 | * Routines made available to TIPC by supported media types | 169 | * Routines made available to TIPC by supported media types |
| 174 | */ | 170 | */ |
| 175 | int tipc_eth_media_start(void); | 171 | extern struct tipc_media eth_media_info; |
| 176 | void tipc_eth_media_stop(void); | ||
| 177 | 172 | ||
| 178 | #ifdef CONFIG_TIPC_MEDIA_IB | 173 | #ifdef CONFIG_TIPC_MEDIA_IB |
| 179 | int tipc_ib_media_start(void); | 174 | extern struct tipc_media ib_media_info; |
| 180 | void tipc_ib_media_stop(void); | ||
| 181 | #else | ||
| 182 | static inline int tipc_ib_media_start(void) { return 0; } | ||
| 183 | static inline void tipc_ib_media_stop(void) { return; } | ||
| 184 | #endif | 175 | #endif |
| 185 | 176 | ||
| 186 | int tipc_media_set_priority(const char *name, u32 new_value); | 177 | int tipc_media_set_priority(const char *name, u32 new_value); |
| 187 | int tipc_media_set_window(const char *name, u32 new_value); | 178 | int tipc_media_set_window(const char *name, u32 new_value); |
| 188 | void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); | 179 | void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); |
| 189 | struct sk_buff *tipc_media_get_names(void); | 180 | struct sk_buff *tipc_media_get_names(void); |
| 181 | void tipc_l2_media_addr_set(const struct tipc_bearer *b, | ||
| 182 | struct tipc_media_addr *a, char *mac); | ||
| 183 | int tipc_enable_l2_media(struct tipc_bearer *b); | ||
| 184 | void tipc_disable_l2_media(struct tipc_bearer *b); | ||
| 185 | int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b, | ||
| 186 | struct tipc_media_addr *dest); | ||
| 190 | 187 | ||
| 191 | struct sk_buff *tipc_bearer_get_names(void); | 188 | struct sk_buff *tipc_bearer_get_names(void); |
| 192 | void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest); | 189 | void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest); |
| 193 | void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest); | 190 | void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest); |
| 194 | struct tipc_bearer *tipc_bearer_find(const char *name); | 191 | struct tipc_bearer *tipc_bearer_find(const char *name); |
| 195 | struct tipc_bearer *tipc_bearer_find_interface(const char *if_name); | ||
| 196 | struct tipc_media *tipc_media_find(const char *name); | 192 | struct tipc_media *tipc_media_find(const char *name); |
| 197 | int tipc_bearer_blocked(struct tipc_bearer *b_ptr); | 193 | int tipc_bearer_setup(void); |
| 194 | void tipc_bearer_cleanup(void); | ||
| 198 | void tipc_bearer_stop(void); | 195 | void tipc_bearer_stop(void); |
| 199 | 196 | void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, | |
| 200 | /** | 197 | struct tipc_media_addr *dest); |
| 201 | * tipc_bearer_send- sends buffer to destination over bearer | ||
| 202 | * | ||
| 203 | * IMPORTANT: | ||
| 204 | * The media send routine must not alter the buffer being passed in | ||
| 205 | * as it may be needed for later retransmission! | ||
| 206 | */ | ||
| 207 | static inline void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf, | ||
| 208 | struct tipc_media_addr *dest) | ||
| 209 | { | ||
| 210 | b->media->send_msg(buf, b, dest); | ||
| 211 | } | ||
| 212 | 198 | ||
| 213 | #endif /* _TIPC_BEARER_H */ | 199 | #endif /* _TIPC_BEARER_H */ |
diff --git a/net/tipc/config.c b/net/tipc/config.c index c301a9a592d8..e6d721692ae0 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c | |||
| @@ -181,7 +181,7 @@ static struct sk_buff *cfg_set_own_addr(void) | |||
| 181 | if (tipc_own_addr) | 181 | if (tipc_own_addr) |
| 182 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | 182 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED |
| 183 | " (cannot change node address once assigned)"); | 183 | " (cannot change node address once assigned)"); |
| 184 | tipc_core_start_net(addr); | 184 | tipc_net_start(addr); |
| 185 | return tipc_cfg_reply_none(); | 185 | return tipc_cfg_reply_none(); |
| 186 | } | 186 | } |
| 187 | 187 | ||
| @@ -376,7 +376,6 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr, | |||
| 376 | struct tipc_cfg_msg_hdr *req_hdr; | 376 | struct tipc_cfg_msg_hdr *req_hdr; |
| 377 | struct tipc_cfg_msg_hdr *rep_hdr; | 377 | struct tipc_cfg_msg_hdr *rep_hdr; |
| 378 | struct sk_buff *rep_buf; | 378 | struct sk_buff *rep_buf; |
| 379 | int ret; | ||
| 380 | 379 | ||
| 381 | /* Validate configuration message header (ignore invalid message) */ | 380 | /* Validate configuration message header (ignore invalid message) */ |
| 382 | req_hdr = (struct tipc_cfg_msg_hdr *)buf; | 381 | req_hdr = (struct tipc_cfg_msg_hdr *)buf; |
| @@ -398,12 +397,8 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr, | |||
| 398 | memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); | 397 | memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); |
| 399 | rep_hdr->tcm_len = htonl(rep_buf->len); | 398 | rep_hdr->tcm_len = htonl(rep_buf->len); |
| 400 | rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); | 399 | rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); |
| 401 | 400 | tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data, | |
| 402 | ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data, | 401 | rep_buf->len); |
| 403 | rep_buf->len); | ||
| 404 | if (ret < 0) | ||
| 405 | pr_err("Sending cfg reply message failed, no memory\n"); | ||
| 406 | |||
| 407 | kfree_skb(rep_buf); | 402 | kfree_skb(rep_buf); |
| 408 | } | 403 | } |
| 409 | } | 404 | } |
diff --git a/net/tipc/core.c b/net/tipc/core.c index c6d3f75a9e1b..80c20647b3d2 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c | |||
| @@ -77,41 +77,13 @@ struct sk_buff *tipc_buf_acquire(u32 size) | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | /** | 79 | /** |
| 80 | * tipc_core_stop_net - shut down TIPC networking sub-systems | ||
| 81 | */ | ||
| 82 | static void tipc_core_stop_net(void) | ||
| 83 | { | ||
| 84 | tipc_net_stop(); | ||
| 85 | tipc_eth_media_stop(); | ||
| 86 | tipc_ib_media_stop(); | ||
| 87 | } | ||
| 88 | |||
| 89 | /** | ||
| 90 | * start_net - start TIPC networking sub-systems | ||
| 91 | */ | ||
| 92 | int tipc_core_start_net(unsigned long addr) | ||
| 93 | { | ||
| 94 | int res; | ||
| 95 | |||
| 96 | tipc_net_start(addr); | ||
| 97 | res = tipc_eth_media_start(); | ||
| 98 | if (res < 0) | ||
| 99 | goto err; | ||
| 100 | res = tipc_ib_media_start(); | ||
| 101 | if (res < 0) | ||
| 102 | goto err; | ||
| 103 | return res; | ||
| 104 | |||
| 105 | err: | ||
| 106 | tipc_core_stop_net(); | ||
| 107 | return res; | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode | 80 | * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode |
| 112 | */ | 81 | */ |
| 113 | static void tipc_core_stop(void) | 82 | static void tipc_core_stop(void) |
| 114 | { | 83 | { |
| 84 | tipc_handler_stop(); | ||
| 85 | tipc_net_stop(); | ||
| 86 | tipc_bearer_cleanup(); | ||
| 115 | tipc_netlink_stop(); | 87 | tipc_netlink_stop(); |
| 116 | tipc_cfg_stop(); | 88 | tipc_cfg_stop(); |
| 117 | tipc_subscr_stop(); | 89 | tipc_subscr_stop(); |
| @@ -126,30 +98,65 @@ static void tipc_core_stop(void) | |||
| 126 | */ | 98 | */ |
| 127 | static int tipc_core_start(void) | 99 | static int tipc_core_start(void) |
| 128 | { | 100 | { |
| 129 | int res; | 101 | int err; |
| 130 | 102 | ||
| 131 | get_random_bytes(&tipc_random, sizeof(tipc_random)); | 103 | get_random_bytes(&tipc_random, sizeof(tipc_random)); |
| 132 | 104 | ||
| 133 | res = tipc_handler_start(); | 105 | err = tipc_handler_start(); |
| 134 | if (!res) | 106 | if (err) |
| 135 | res = tipc_ref_table_init(tipc_max_ports, tipc_random); | 107 | goto out_handler; |
| 136 | if (!res) | 108 | |
| 137 | res = tipc_nametbl_init(); | 109 | err = tipc_ref_table_init(tipc_max_ports, tipc_random); |
| 138 | if (!res) | 110 | if (err) |
| 139 | res = tipc_netlink_start(); | 111 | goto out_reftbl; |
| 140 | if (!res) | 112 | |
| 141 | res = tipc_socket_init(); | 113 | err = tipc_nametbl_init(); |
| 142 | if (!res) | 114 | if (err) |
| 143 | res = tipc_register_sysctl(); | 115 | goto out_nametbl; |
| 144 | if (!res) | 116 | |
| 145 | res = tipc_subscr_start(); | 117 | err = tipc_netlink_start(); |
| 146 | if (!res) | 118 | if (err) |
| 147 | res = tipc_cfg_init(); | 119 | goto out_netlink; |
| 148 | if (res) { | 120 | |
| 149 | tipc_handler_stop(); | 121 | err = tipc_socket_init(); |
| 150 | tipc_core_stop(); | 122 | if (err) |
| 151 | } | 123 | goto out_socket; |
| 152 | return res; | 124 | |
| 125 | err = tipc_register_sysctl(); | ||
| 126 | if (err) | ||
| 127 | goto out_sysctl; | ||
| 128 | |||
| 129 | err = tipc_subscr_start(); | ||
| 130 | if (err) | ||
| 131 | goto out_subscr; | ||
| 132 | |||
| 133 | err = tipc_cfg_init(); | ||
| 134 | if (err) | ||
| 135 | goto out_cfg; | ||
| 136 | |||
| 137 | err = tipc_bearer_setup(); | ||
| 138 | if (err) | ||
| 139 | goto out_bearer; | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | out_bearer: | ||
| 143 | tipc_cfg_stop(); | ||
| 144 | out_cfg: | ||
| 145 | tipc_subscr_stop(); | ||
| 146 | out_subscr: | ||
| 147 | tipc_unregister_sysctl(); | ||
| 148 | out_sysctl: | ||
| 149 | tipc_socket_stop(); | ||
| 150 | out_socket: | ||
| 151 | tipc_netlink_stop(); | ||
| 152 | out_netlink: | ||
| 153 | tipc_nametbl_stop(); | ||
| 154 | out_nametbl: | ||
| 155 | tipc_ref_table_stop(); | ||
| 156 | out_reftbl: | ||
| 157 | tipc_handler_stop(); | ||
| 158 | out_handler: | ||
| 159 | return err; | ||
| 153 | } | 160 | } |
| 154 | 161 | ||
| 155 | static int __init tipc_init(void) | 162 | static int __init tipc_init(void) |
| @@ -178,8 +185,6 @@ static int __init tipc_init(void) | |||
| 178 | 185 | ||
| 179 | static void __exit tipc_exit(void) | 186 | static void __exit tipc_exit(void) |
| 180 | { | 187 | { |
| 181 | tipc_handler_stop(); | ||
| 182 | tipc_core_stop_net(); | ||
| 183 | tipc_core_stop(); | 188 | tipc_core_stop(); |
| 184 | pr_info("Deactivated\n"); | 189 | pr_info("Deactivated\n"); |
| 185 | } | 190 | } |
diff --git a/net/tipc/core.h b/net/tipc/core.h index 94895d4e86ab..4dfe137587bb 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h | |||
| @@ -47,7 +47,7 @@ | |||
| 47 | #include <linux/mm.h> | 47 | #include <linux/mm.h> |
| 48 | #include <linux/timer.h> | 48 | #include <linux/timer.h> |
| 49 | #include <linux/string.h> | 49 | #include <linux/string.h> |
| 50 | #include <asm/uaccess.h> | 50 | #include <linux/uaccess.h> |
| 51 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
| 52 | #include <linux/atomic.h> | 52 | #include <linux/atomic.h> |
| 53 | #include <asm/hardirq.h> | 53 | #include <asm/hardirq.h> |
| @@ -90,7 +90,6 @@ extern int tipc_random __read_mostly; | |||
| 90 | /* | 90 | /* |
| 91 | * Routines available to privileged subsystems | 91 | * Routines available to privileged subsystems |
| 92 | */ | 92 | */ |
| 93 | int tipc_core_start_net(unsigned long); | ||
| 94 | int tipc_handler_start(void); | 93 | int tipc_handler_start(void); |
| 95 | void tipc_handler_stop(void); | 94 | void tipc_handler_stop(void); |
| 96 | int tipc_netlink_start(void); | 95 | int tipc_netlink_start(void); |
| @@ -192,6 +191,7 @@ static inline void k_term_timer(struct timer_list *timer) | |||
| 192 | 191 | ||
| 193 | struct tipc_skb_cb { | 192 | struct tipc_skb_cb { |
| 194 | void *handle; | 193 | void *handle; |
| 194 | bool deferred; | ||
| 195 | }; | 195 | }; |
| 196 | 196 | ||
| 197 | #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0])) | 197 | #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0])) |
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index ecc758c6eacf..412ff41b8611 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | * @dest: destination address for request messages | 50 | * @dest: destination address for request messages |
| 51 | * @domain: network domain to which links can be established | 51 | * @domain: network domain to which links can be established |
| 52 | * @num_nodes: number of nodes currently discovered (i.e. with an active link) | 52 | * @num_nodes: number of nodes currently discovered (i.e. with an active link) |
| 53 | * @lock: spinlock for controlling access to requests | ||
| 53 | * @buf: request message to be (repeatedly) sent | 54 | * @buf: request message to be (repeatedly) sent |
| 54 | * @timer: timer governing period between requests | 55 | * @timer: timer governing period between requests |
| 55 | * @timer_intv: current interval between requests (in ms) | 56 | * @timer_intv: current interval between requests (in ms) |
| @@ -59,6 +60,7 @@ struct tipc_link_req { | |||
| 59 | struct tipc_media_addr dest; | 60 | struct tipc_media_addr dest; |
| 60 | u32 domain; | 61 | u32 domain; |
| 61 | int num_nodes; | 62 | int num_nodes; |
| 63 | spinlock_t lock; | ||
| 62 | struct sk_buff *buf; | 64 | struct sk_buff *buf; |
| 63 | struct timer_list timer; | 65 | struct timer_list timer; |
| 64 | unsigned int timer_intv; | 66 | unsigned int timer_intv; |
| @@ -239,7 +241,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) | |||
| 239 | /* Accept discovery message & send response, if necessary */ | 241 | /* Accept discovery message & send response, if necessary */ |
| 240 | link_fully_up = link_working_working(link); | 242 | link_fully_up = link_working_working(link); |
| 241 | 243 | ||
| 242 | if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { | 244 | if ((type == DSC_REQ_MSG) && !link_fully_up) { |
| 243 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); | 245 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); |
| 244 | if (rbuf) { | 246 | if (rbuf) { |
| 245 | tipc_bearer_send(b_ptr, rbuf, &media_addr); | 247 | tipc_bearer_send(b_ptr, rbuf, &media_addr); |
| @@ -274,7 +276,9 @@ static void disc_update(struct tipc_link_req *req) | |||
| 274 | */ | 276 | */ |
| 275 | void tipc_disc_add_dest(struct tipc_link_req *req) | 277 | void tipc_disc_add_dest(struct tipc_link_req *req) |
| 276 | { | 278 | { |
| 279 | spin_lock_bh(&req->lock); | ||
| 277 | req->num_nodes++; | 280 | req->num_nodes++; |
| 281 | spin_unlock_bh(&req->lock); | ||
| 278 | } | 282 | } |
| 279 | 283 | ||
| 280 | /** | 284 | /** |
| @@ -283,18 +287,10 @@ void tipc_disc_add_dest(struct tipc_link_req *req) | |||
| 283 | */ | 287 | */ |
| 284 | void tipc_disc_remove_dest(struct tipc_link_req *req) | 288 | void tipc_disc_remove_dest(struct tipc_link_req *req) |
| 285 | { | 289 | { |
| 290 | spin_lock_bh(&req->lock); | ||
| 286 | req->num_nodes--; | 291 | req->num_nodes--; |
| 287 | disc_update(req); | 292 | disc_update(req); |
| 288 | } | 293 | spin_unlock_bh(&req->lock); |
| 289 | |||
| 290 | /** | ||
| 291 | * disc_send_msg - send link setup request message | ||
| 292 | * @req: ptr to link request structure | ||
| 293 | */ | ||
| 294 | static void disc_send_msg(struct tipc_link_req *req) | ||
| 295 | { | ||
| 296 | if (!req->bearer->blocked) | ||
| 297 | tipc_bearer_send(req->bearer, req->buf, &req->dest); | ||
| 298 | } | 294 | } |
| 299 | 295 | ||
| 300 | /** | 296 | /** |
| @@ -307,7 +303,7 @@ static void disc_timeout(struct tipc_link_req *req) | |||
| 307 | { | 303 | { |
| 308 | int max_delay; | 304 | int max_delay; |
| 309 | 305 | ||
| 310 | spin_lock_bh(&req->bearer->lock); | 306 | spin_lock_bh(&req->lock); |
| 311 | 307 | ||
| 312 | /* Stop searching if only desired node has been found */ | 308 | /* Stop searching if only desired node has been found */ |
| 313 | if (tipc_node(req->domain) && req->num_nodes) { | 309 | if (tipc_node(req->domain) && req->num_nodes) { |
| @@ -322,7 +318,8 @@ static void disc_timeout(struct tipc_link_req *req) | |||
| 322 | * hold at fast polling rate if don't have any associated nodes, | 318 | * hold at fast polling rate if don't have any associated nodes, |
| 323 | * otherwise hold at slow polling rate | 319 | * otherwise hold at slow polling rate |
| 324 | */ | 320 | */ |
| 325 | disc_send_msg(req); | 321 | tipc_bearer_send(req->bearer, req->buf, &req->dest); |
| 322 | |||
| 326 | 323 | ||
| 327 | req->timer_intv *= 2; | 324 | req->timer_intv *= 2; |
| 328 | if (req->num_nodes) | 325 | if (req->num_nodes) |
| @@ -334,7 +331,7 @@ static void disc_timeout(struct tipc_link_req *req) | |||
| 334 | 331 | ||
| 335 | k_start_timer(&req->timer, req->timer_intv); | 332 | k_start_timer(&req->timer, req->timer_intv); |
| 336 | exit: | 333 | exit: |
| 337 | spin_unlock_bh(&req->bearer->lock); | 334 | spin_unlock_bh(&req->lock); |
| 338 | } | 335 | } |
| 339 | 336 | ||
| 340 | /** | 337 | /** |
| @@ -365,10 +362,11 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest, | |||
| 365 | req->domain = dest_domain; | 362 | req->domain = dest_domain; |
| 366 | req->num_nodes = 0; | 363 | req->num_nodes = 0; |
| 367 | req->timer_intv = TIPC_LINK_REQ_INIT; | 364 | req->timer_intv = TIPC_LINK_REQ_INIT; |
| 365 | spin_lock_init(&req->lock); | ||
| 368 | k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); | 366 | k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); |
| 369 | k_start_timer(&req->timer, req->timer_intv); | 367 | k_start_timer(&req->timer, req->timer_intv); |
| 370 | b_ptr->link_req = req; | 368 | b_ptr->link_req = req; |
| 371 | disc_send_msg(req); | 369 | tipc_bearer_send(req->bearer, req->buf, &req->dest); |
| 372 | return 0; | 370 | return 0; |
| 373 | } | 371 | } |
| 374 | 372 | ||
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index f80d59f5a161..67cf3f935dba 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/eth_media.c: Ethernet bearer support for TIPC | 2 | * net/tipc/eth_media.c: Ethernet bearer support for TIPC |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2001-2007, Ericsson AB | 4 | * Copyright (c) 2001-2007, 2013, Ericsson AB |
| 5 | * Copyright (c) 2005-2008, 2011-2013, Wind River Systems | 5 | * Copyright (c) 2005-2008, 2011-2013, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -37,259 +37,11 @@ | |||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "bearer.h" | 38 | #include "bearer.h" |
| 39 | 39 | ||
| 40 | #define MAX_ETH_MEDIA MAX_BEARERS | ||
| 41 | |||
| 42 | #define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */ | 40 | #define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */ |
| 43 | 41 | ||
| 44 | /** | 42 | /* convert Ethernet address to string */ |
| 45 | * struct eth_media - Ethernet bearer data structure | 43 | static int tipc_eth_addr2str(struct tipc_media_addr *a, char *str_buf, |
| 46 | * @bearer: ptr to associated "generic" bearer structure | 44 | int str_size) |
| 47 | * @dev: ptr to associated Ethernet network device | ||
| 48 | * @tipc_packet_type: used in binding TIPC to Ethernet driver | ||
| 49 | * @setup: work item used when enabling bearer | ||
| 50 | * @cleanup: work item used when disabling bearer | ||
| 51 | */ | ||
| 52 | struct eth_media { | ||
| 53 | struct tipc_bearer *bearer; | ||
| 54 | struct net_device *dev; | ||
| 55 | struct packet_type tipc_packet_type; | ||
| 56 | struct work_struct setup; | ||
| 57 | struct work_struct cleanup; | ||
| 58 | }; | ||
| 59 | |||
| 60 | static struct tipc_media eth_media_info; | ||
| 61 | static struct eth_media eth_media_array[MAX_ETH_MEDIA]; | ||
| 62 | static int eth_started; | ||
| 63 | |||
| 64 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | ||
| 65 | void *dv); | ||
| 66 | /* | ||
| 67 | * Network device notifier info | ||
| 68 | */ | ||
| 69 | static struct notifier_block notifier = { | ||
| 70 | .notifier_call = recv_notification, | ||
| 71 | .priority = 0 | ||
| 72 | }; | ||
| 73 | |||
| 74 | /** | ||
| 75 | * eth_media_addr_set - initialize Ethernet media address structure | ||
| 76 | * | ||
| 77 | * Media-dependent "value" field stores MAC address in first 6 bytes | ||
| 78 | * and zeroes out the remaining bytes. | ||
| 79 | */ | ||
| 80 | static void eth_media_addr_set(const struct tipc_bearer *tb_ptr, | ||
| 81 | struct tipc_media_addr *a, char *mac) | ||
| 82 | { | ||
| 83 | memcpy(a->value, mac, ETH_ALEN); | ||
| 84 | memset(a->value + ETH_ALEN, 0, sizeof(a->value) - ETH_ALEN); | ||
| 85 | a->media_id = TIPC_MEDIA_TYPE_ETH; | ||
| 86 | a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, ETH_ALEN); | ||
| 87 | } | ||
| 88 | |||
| 89 | /** | ||
| 90 | * send_msg - send a TIPC message out over an Ethernet interface | ||
| 91 | */ | ||
| 92 | static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, | ||
| 93 | struct tipc_media_addr *dest) | ||
| 94 | { | ||
| 95 | struct sk_buff *clone; | ||
| 96 | struct net_device *dev; | ||
| 97 | int delta; | ||
| 98 | |||
| 99 | clone = skb_clone(buf, GFP_ATOMIC); | ||
| 100 | if (!clone) | ||
| 101 | return 0; | ||
| 102 | |||
| 103 | dev = ((struct eth_media *)(tb_ptr->usr_handle))->dev; | ||
| 104 | delta = dev->hard_header_len - skb_headroom(buf); | ||
| 105 | |||
| 106 | if ((delta > 0) && | ||
| 107 | pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { | ||
| 108 | kfree_skb(clone); | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | skb_reset_network_header(clone); | ||
| 113 | clone->dev = dev; | ||
| 114 | clone->protocol = htons(ETH_P_TIPC); | ||
| 115 | dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, | ||
| 116 | dev->dev_addr, clone->len); | ||
| 117 | dev_queue_xmit(clone); | ||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | /** | ||
| 122 | * recv_msg - handle incoming TIPC message from an Ethernet interface | ||
| 123 | * | ||
| 124 | * Accept only packets explicitly sent to this node, or broadcast packets; | ||
| 125 | * ignores packets sent using Ethernet multicast, and traffic sent to other | ||
| 126 | * nodes (which can happen if interface is running in promiscuous mode). | ||
| 127 | */ | ||
| 128 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | ||
| 129 | struct packet_type *pt, struct net_device *orig_dev) | ||
| 130 | { | ||
| 131 | struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv; | ||
| 132 | |||
| 133 | if (!net_eq(dev_net(dev), &init_net)) { | ||
| 134 | kfree_skb(buf); | ||
| 135 | return NET_RX_DROP; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (likely(eb_ptr->bearer)) { | ||
| 139 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | ||
| 140 | buf->next = NULL; | ||
| 141 | tipc_recv_msg(buf, eb_ptr->bearer); | ||
| 142 | return NET_RX_SUCCESS; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | kfree_skb(buf); | ||
| 146 | return NET_RX_DROP; | ||
| 147 | } | ||
| 148 | |||
| 149 | /** | ||
| 150 | * setup_media - setup association between Ethernet bearer and interface | ||
| 151 | */ | ||
| 152 | static void setup_media(struct work_struct *work) | ||
| 153 | { | ||
| 154 | struct eth_media *eb_ptr = | ||
| 155 | container_of(work, struct eth_media, setup); | ||
| 156 | |||
| 157 | dev_add_pack(&eb_ptr->tipc_packet_type); | ||
| 158 | } | ||
| 159 | |||
| 160 | /** | ||
| 161 | * enable_media - attach TIPC bearer to an Ethernet interface | ||
| 162 | */ | ||
| 163 | static int enable_media(struct tipc_bearer *tb_ptr) | ||
| 164 | { | ||
| 165 | struct net_device *dev; | ||
| 166 | struct eth_media *eb_ptr = ð_media_array[0]; | ||
| 167 | struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; | ||
| 168 | char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; | ||
| 169 | int pending_dev = 0; | ||
| 170 | |||
| 171 | /* Find unused Ethernet bearer structure */ | ||
| 172 | while (eb_ptr->dev) { | ||
| 173 | if (!eb_ptr->bearer) | ||
| 174 | pending_dev++; | ||
| 175 | if (++eb_ptr == stop) | ||
| 176 | return pending_dev ? -EAGAIN : -EDQUOT; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* Find device with specified name */ | ||
| 180 | dev = dev_get_by_name(&init_net, driver_name); | ||
| 181 | if (!dev) | ||
| 182 | return -ENODEV; | ||
| 183 | |||
| 184 | /* Create Ethernet bearer for device */ | ||
| 185 | 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); | ||
| 192 | schedule_work(&eb_ptr->setup); | ||
| 193 | |||
| 194 | /* Associate TIPC bearer with Ethernet bearer */ | ||
| 195 | eb_ptr->bearer = tb_ptr; | ||
| 196 | tb_ptr->usr_handle = (void *)eb_ptr; | ||
| 197 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); | ||
| 198 | memcpy(tb_ptr->bcast_addr.value, dev->broadcast, ETH_ALEN); | ||
| 199 | tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH; | ||
| 200 | tb_ptr->bcast_addr.broadcast = 1; | ||
| 201 | tb_ptr->mtu = dev->mtu; | ||
| 202 | tb_ptr->blocked = 0; | ||
| 203 | eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | /** | ||
| 208 | * cleanup_media - break association between Ethernet bearer and interface | ||
| 209 | * | ||
| 210 | * This routine must be invoked from a work queue because it can sleep. | ||
| 211 | */ | ||
| 212 | static void cleanup_media(struct work_struct *work) | ||
| 213 | { | ||
| 214 | struct eth_media *eb_ptr = | ||
| 215 | container_of(work, struct eth_media, cleanup); | ||
| 216 | |||
| 217 | dev_remove_pack(&eb_ptr->tipc_packet_type); | ||
| 218 | dev_put(eb_ptr->dev); | ||
| 219 | eb_ptr->dev = NULL; | ||
| 220 | } | ||
| 221 | |||
| 222 | /** | ||
| 223 | * disable_media - detach TIPC bearer from an Ethernet interface | ||
| 224 | * | ||
| 225 | * Mark Ethernet bearer as inactive so that incoming buffers are thrown away, | ||
| 226 | * then get worker thread to complete bearer cleanup. (Can't do cleanup | ||
| 227 | * here because cleanup code needs to sleep and caller holds spinlocks.) | ||
| 228 | */ | ||
| 229 | static void disable_media(struct tipc_bearer *tb_ptr) | ||
| 230 | { | ||
| 231 | struct eth_media *eb_ptr = (struct eth_media *)tb_ptr->usr_handle; | ||
| 232 | |||
| 233 | eb_ptr->bearer = NULL; | ||
| 234 | INIT_WORK(&eb_ptr->cleanup, cleanup_media); | ||
| 235 | schedule_work(&eb_ptr->cleanup); | ||
| 236 | } | ||
| 237 | |||
| 238 | /** | ||
| 239 | * recv_notification - handle device updates from OS | ||
| 240 | * | ||
| 241 | * Change the state of the Ethernet bearer (if any) associated with the | ||
| 242 | * specified device. | ||
| 243 | */ | ||
| 244 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | ||
| 245 | void *ptr) | ||
| 246 | { | ||
| 247 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 248 | struct eth_media *eb_ptr = ð_media_array[0]; | ||
| 249 | struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; | ||
| 250 | |||
| 251 | if (!net_eq(dev_net(dev), &init_net)) | ||
| 252 | return NOTIFY_DONE; | ||
| 253 | |||
| 254 | while ((eb_ptr->dev != dev)) { | ||
| 255 | if (++eb_ptr == stop) | ||
| 256 | return NOTIFY_DONE; /* couldn't find device */ | ||
| 257 | } | ||
| 258 | if (!eb_ptr->bearer) | ||
| 259 | return NOTIFY_DONE; /* bearer had been disabled */ | ||
| 260 | |||
| 261 | eb_ptr->bearer->mtu = dev->mtu; | ||
| 262 | |||
| 263 | switch (evt) { | ||
| 264 | case NETDEV_CHANGE: | ||
| 265 | if (netif_carrier_ok(dev)) | ||
| 266 | tipc_continue(eb_ptr->bearer); | ||
| 267 | else | ||
| 268 | tipc_block_bearer(eb_ptr->bearer); | ||
| 269 | break; | ||
| 270 | case NETDEV_UP: | ||
| 271 | tipc_continue(eb_ptr->bearer); | ||
| 272 | break; | ||
| 273 | case NETDEV_DOWN: | ||
| 274 | tipc_block_bearer(eb_ptr->bearer); | ||
| 275 | break; | ||
| 276 | case NETDEV_CHANGEMTU: | ||
| 277 | case NETDEV_CHANGEADDR: | ||
| 278 | tipc_block_bearer(eb_ptr->bearer); | ||
| 279 | tipc_continue(eb_ptr->bearer); | ||
| 280 | break; | ||
| 281 | case NETDEV_UNREGISTER: | ||
| 282 | case NETDEV_CHANGENAME: | ||
| 283 | tipc_disable_bearer(eb_ptr->bearer->name); | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | return NOTIFY_OK; | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * eth_addr2str - convert Ethernet address to string | ||
| 291 | */ | ||
| 292 | static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | ||
| 293 | { | 45 | { |
| 294 | if (str_size < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */ | 46 | if (str_size < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */ |
| 295 | return 1; | 47 | return 1; |
| @@ -298,10 +50,8 @@ static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | |||
| 298 | return 0; | 50 | return 0; |
| 299 | } | 51 | } |
| 300 | 52 | ||
| 301 | /** | 53 | /* convert Ethernet address format to message header format */ |
| 302 | * eth_str2addr - convert Ethernet address format to message header format | 54 | static int tipc_eth_addr2msg(struct tipc_media_addr *a, char *msg_area) |
| 303 | */ | ||
| 304 | static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area) | ||
| 305 | { | 55 | { |
| 306 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); | 56 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); |
| 307 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH; | 57 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH; |
| @@ -309,68 +59,30 @@ static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area) | |||
| 309 | return 0; | 59 | return 0; |
| 310 | } | 60 | } |
| 311 | 61 | ||
| 312 | /** | 62 | /* convert message header address format to Ethernet format */ |
| 313 | * eth_str2addr - convert message header address format to Ethernet format | 63 | static int tipc_eth_msg2addr(const struct tipc_bearer *tb_ptr, |
| 314 | */ | 64 | struct tipc_media_addr *a, char *msg_area) |
| 315 | static int eth_msg2addr(const struct tipc_bearer *tb_ptr, | ||
| 316 | struct tipc_media_addr *a, char *msg_area) | ||
| 317 | { | 65 | { |
| 318 | if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH) | 66 | if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH) |
| 319 | return 1; | 67 | return 1; |
| 320 | 68 | ||
| 321 | eth_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET); | 69 | tipc_l2_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET); |
| 322 | return 0; | 70 | return 0; |
| 323 | } | 71 | } |
| 324 | 72 | ||
| 325 | /* | 73 | /* Ethernet media registration info */ |
| 326 | * Ethernet media registration info | 74 | struct tipc_media eth_media_info = { |
| 327 | */ | 75 | .send_msg = tipc_l2_send_msg, |
| 328 | static struct tipc_media eth_media_info = { | 76 | .enable_media = tipc_enable_l2_media, |
| 329 | .send_msg = send_msg, | 77 | .disable_media = tipc_disable_l2_media, |
| 330 | .enable_media = enable_media, | 78 | .addr2str = tipc_eth_addr2str, |
| 331 | .disable_media = disable_media, | 79 | .addr2msg = tipc_eth_addr2msg, |
| 332 | .addr2str = eth_addr2str, | 80 | .msg2addr = tipc_eth_msg2addr, |
| 333 | .addr2msg = eth_addr2msg, | ||
| 334 | .msg2addr = eth_msg2addr, | ||
| 335 | .priority = TIPC_DEF_LINK_PRI, | 81 | .priority = TIPC_DEF_LINK_PRI, |
| 336 | .tolerance = TIPC_DEF_LINK_TOL, | 82 | .tolerance = TIPC_DEF_LINK_TOL, |
| 337 | .window = TIPC_DEF_LINK_WIN, | 83 | .window = TIPC_DEF_LINK_WIN, |
| 338 | .type_id = TIPC_MEDIA_TYPE_ETH, | 84 | .type_id = TIPC_MEDIA_TYPE_ETH, |
| 85 | .hwaddr_len = ETH_ALEN, | ||
| 339 | .name = "eth" | 86 | .name = "eth" |
| 340 | }; | 87 | }; |
| 341 | 88 | ||
| 342 | /** | ||
| 343 | * tipc_eth_media_start - activate Ethernet bearer support | ||
| 344 | * | ||
| 345 | * Register Ethernet media type with TIPC bearer code. Also register | ||
| 346 | * with OS for notifications about device state changes. | ||
| 347 | */ | ||
| 348 | int tipc_eth_media_start(void) | ||
| 349 | { | ||
| 350 | int res; | ||
| 351 | |||
| 352 | if (eth_started) | ||
| 353 | return -EINVAL; | ||
| 354 | |||
| 355 | res = tipc_register_media(ð_media_info); | ||
| 356 | if (res) | ||
| 357 | return res; | ||
| 358 | |||
| 359 | res = register_netdevice_notifier(¬ifier); | ||
| 360 | if (!res) | ||
| 361 | eth_started = 1; | ||
| 362 | return res; | ||
| 363 | } | ||
| 364 | |||
| 365 | /** | ||
| 366 | * tipc_eth_media_stop - deactivate Ethernet bearer support | ||
| 367 | */ | ||
| 368 | void tipc_eth_media_stop(void) | ||
| 369 | { | ||
| 370 | if (!eth_started) | ||
| 371 | return; | ||
| 372 | |||
| 373 | flush_scheduled_work(); | ||
| 374 | unregister_netdevice_notifier(¬ifier); | ||
| 375 | eth_started = 0; | ||
| 376 | } | ||
diff --git a/net/tipc/handler.c b/net/tipc/handler.c index e4bc8a296744..1fabf160501f 100644 --- a/net/tipc/handler.c +++ b/net/tipc/handler.c | |||
| @@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument) | |||
| 58 | 58 | ||
| 59 | spin_lock_bh(&qitem_lock); | 59 | spin_lock_bh(&qitem_lock); |
| 60 | if (!handler_enabled) { | 60 | if (!handler_enabled) { |
| 61 | pr_err("Signal request ignored by handler\n"); | ||
| 62 | spin_unlock_bh(&qitem_lock); | 61 | spin_unlock_bh(&qitem_lock); |
| 63 | return -ENOPROTOOPT; | 62 | return -ENOPROTOOPT; |
| 64 | } | 63 | } |
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index c13989297464..844a77e25828 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c | |||
| @@ -42,252 +42,9 @@ | |||
| 42 | #include "core.h" | 42 | #include "core.h" |
| 43 | #include "bearer.h" | 43 | #include "bearer.h" |
| 44 | 44 | ||
| 45 | #define MAX_IB_MEDIA MAX_BEARERS | 45 | /* convert InfiniBand address to string */ |
| 46 | 46 | static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf, | |
| 47 | /** | 47 | int str_size) |
| 48 | * struct ib_media - Infiniband media data structure | ||
| 49 | * @bearer: ptr to associated "generic" bearer structure | ||
| 50 | * @dev: ptr to associated Infiniband network device | ||
| 51 | * @tipc_packet_type: used in binding TIPC to Infiniband driver | ||
| 52 | * @cleanup: work item used when disabling bearer | ||
| 53 | */ | ||
| 54 | |||
| 55 | struct ib_media { | ||
| 56 | struct tipc_bearer *bearer; | ||
| 57 | struct net_device *dev; | ||
| 58 | struct packet_type tipc_packet_type; | ||
| 59 | struct work_struct setup; | ||
| 60 | struct work_struct cleanup; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static struct tipc_media ib_media_info; | ||
| 64 | static struct ib_media ib_media_array[MAX_IB_MEDIA]; | ||
| 65 | static int ib_started; | ||
| 66 | |||
| 67 | /** | ||
| 68 | * ib_media_addr_set - initialize Infiniband media address structure | ||
| 69 | * | ||
| 70 | * Media-dependent "value" field stores MAC address in first 6 bytes | ||
| 71 | * and zeroes out the remaining bytes. | ||
| 72 | */ | ||
| 73 | static void ib_media_addr_set(const struct tipc_bearer *tb_ptr, | ||
| 74 | struct tipc_media_addr *a, char *mac) | ||
| 75 | { | ||
| 76 | BUILD_BUG_ON(sizeof(a->value) < INFINIBAND_ALEN); | ||
| 77 | memcpy(a->value, mac, INFINIBAND_ALEN); | ||
| 78 | a->media_id = TIPC_MEDIA_TYPE_IB; | ||
| 79 | a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, INFINIBAND_ALEN); | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * send_msg - send a TIPC message out over an InfiniBand interface | ||
| 84 | */ | ||
| 85 | static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, | ||
| 86 | struct tipc_media_addr *dest) | ||
| 87 | { | ||
| 88 | struct sk_buff *clone; | ||
| 89 | struct net_device *dev; | ||
| 90 | int delta; | ||
| 91 | |||
| 92 | clone = skb_clone(buf, GFP_ATOMIC); | ||
| 93 | if (!clone) | ||
| 94 | return 0; | ||
| 95 | |||
| 96 | dev = ((struct ib_media *)(tb_ptr->usr_handle))->dev; | ||
| 97 | delta = dev->hard_header_len - skb_headroom(buf); | ||
| 98 | |||
| 99 | if ((delta > 0) && | ||
| 100 | pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { | ||
| 101 | kfree_skb(clone); | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | skb_reset_network_header(clone); | ||
| 106 | clone->dev = dev; | ||
| 107 | clone->protocol = htons(ETH_P_TIPC); | ||
| 108 | dev_hard_header(clone, dev, ETH_P_TIPC, dest->value, | ||
| 109 | dev->dev_addr, clone->len); | ||
| 110 | dev_queue_xmit(clone); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * recv_msg - handle incoming TIPC message from an InfiniBand interface | ||
| 116 | * | ||
| 117 | * Accept only packets explicitly sent to this node, or broadcast packets; | ||
| 118 | * ignores packets sent using InfiniBand multicast, and traffic sent to other | ||
| 119 | * nodes (which can happen if interface is running in promiscuous mode). | ||
| 120 | */ | ||
| 121 | static int recv_msg(struct sk_buff *buf, struct net_device *dev, | ||
| 122 | struct packet_type *pt, struct net_device *orig_dev) | ||
| 123 | { | ||
| 124 | struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv; | ||
| 125 | |||
| 126 | if (!net_eq(dev_net(dev), &init_net)) { | ||
| 127 | kfree_skb(buf); | ||
| 128 | return NET_RX_DROP; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (likely(ib_ptr->bearer)) { | ||
| 132 | if (likely(buf->pkt_type <= PACKET_BROADCAST)) { | ||
| 133 | buf->next = NULL; | ||
| 134 | tipc_recv_msg(buf, ib_ptr->bearer); | ||
| 135 | return NET_RX_SUCCESS; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | kfree_skb(buf); | ||
| 139 | return NET_RX_DROP; | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * setup_bearer - setup association between InfiniBand bearer and interface | ||
| 144 | */ | ||
| 145 | static void setup_media(struct work_struct *work) | ||
| 146 | { | ||
| 147 | struct ib_media *ib_ptr = | ||
| 148 | container_of(work, struct ib_media, setup); | ||
| 149 | |||
| 150 | dev_add_pack(&ib_ptr->tipc_packet_type); | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * enable_media - attach TIPC bearer to an InfiniBand interface | ||
| 155 | */ | ||
| 156 | static int enable_media(struct tipc_bearer *tb_ptr) | ||
| 157 | { | ||
| 158 | struct net_device *dev; | ||
| 159 | struct ib_media *ib_ptr = &ib_media_array[0]; | ||
| 160 | struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; | ||
| 161 | char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; | ||
| 162 | int pending_dev = 0; | ||
| 163 | |||
| 164 | /* Find unused InfiniBand bearer structure */ | ||
| 165 | while (ib_ptr->dev) { | ||
| 166 | if (!ib_ptr->bearer) | ||
| 167 | pending_dev++; | ||
| 168 | if (++ib_ptr == stop) | ||
| 169 | return pending_dev ? -EAGAIN : -EDQUOT; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Find device with specified name */ | ||
| 173 | dev = dev_get_by_name(&init_net, driver_name); | ||
| 174 | if (!dev) | ||
| 175 | return -ENODEV; | ||
| 176 | |||
| 177 | /* Create InfiniBand bearer for device */ | ||
| 178 | ib_ptr->dev = dev; | ||
| 179 | ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); | ||
| 180 | ib_ptr->tipc_packet_type.dev = dev; | ||
| 181 | ib_ptr->tipc_packet_type.func = recv_msg; | ||
| 182 | ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr; | ||
| 183 | INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list)); | ||
| 184 | INIT_WORK(&ib_ptr->setup, setup_media); | ||
| 185 | schedule_work(&ib_ptr->setup); | ||
| 186 | |||
| 187 | /* Associate TIPC bearer with InfiniBand bearer */ | ||
| 188 | ib_ptr->bearer = tb_ptr; | ||
| 189 | tb_ptr->usr_handle = (void *)ib_ptr; | ||
| 190 | memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); | ||
| 191 | memcpy(tb_ptr->bcast_addr.value, dev->broadcast, INFINIBAND_ALEN); | ||
| 192 | tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB; | ||
| 193 | tb_ptr->bcast_addr.broadcast = 1; | ||
| 194 | tb_ptr->mtu = dev->mtu; | ||
| 195 | tb_ptr->blocked = 0; | ||
| 196 | ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | /** | ||
| 201 | * cleanup_bearer - break association between InfiniBand bearer and interface | ||
| 202 | * | ||
| 203 | * This routine must be invoked from a work queue because it can sleep. | ||
| 204 | */ | ||
| 205 | static void cleanup_bearer(struct work_struct *work) | ||
| 206 | { | ||
| 207 | struct ib_media *ib_ptr = | ||
| 208 | container_of(work, struct ib_media, cleanup); | ||
| 209 | |||
| 210 | dev_remove_pack(&ib_ptr->tipc_packet_type); | ||
| 211 | dev_put(ib_ptr->dev); | ||
| 212 | ib_ptr->dev = NULL; | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | ||
| 216 | * disable_media - detach TIPC bearer from an InfiniBand interface | ||
| 217 | * | ||
| 218 | * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away, | ||
| 219 | * then get worker thread to complete bearer cleanup. (Can't do cleanup | ||
| 220 | * here because cleanup code needs to sleep and caller holds spinlocks.) | ||
| 221 | */ | ||
| 222 | static void disable_media(struct tipc_bearer *tb_ptr) | ||
| 223 | { | ||
| 224 | struct ib_media *ib_ptr = (struct ib_media *)tb_ptr->usr_handle; | ||
| 225 | |||
| 226 | ib_ptr->bearer = NULL; | ||
| 227 | INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); | ||
| 228 | schedule_work(&ib_ptr->cleanup); | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * recv_notification - handle device updates from OS | ||
| 233 | * | ||
| 234 | * Change the state of the InfiniBand bearer (if any) associated with the | ||
| 235 | * specified device. | ||
| 236 | */ | ||
| 237 | static int recv_notification(struct notifier_block *nb, unsigned long evt, | ||
| 238 | void *ptr) | ||
| 239 | { | ||
| 240 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 241 | struct ib_media *ib_ptr = &ib_media_array[0]; | ||
| 242 | struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; | ||
| 243 | |||
| 244 | if (!net_eq(dev_net(dev), &init_net)) | ||
| 245 | return NOTIFY_DONE; | ||
| 246 | |||
| 247 | while ((ib_ptr->dev != dev)) { | ||
| 248 | if (++ib_ptr == stop) | ||
| 249 | return NOTIFY_DONE; /* couldn't find device */ | ||
| 250 | } | ||
| 251 | if (!ib_ptr->bearer) | ||
| 252 | return NOTIFY_DONE; /* bearer had been disabled */ | ||
| 253 | |||
| 254 | ib_ptr->bearer->mtu = dev->mtu; | ||
| 255 | |||
| 256 | switch (evt) { | ||
| 257 | case NETDEV_CHANGE: | ||
| 258 | if (netif_carrier_ok(dev)) | ||
| 259 | tipc_continue(ib_ptr->bearer); | ||
| 260 | else | ||
| 261 | tipc_block_bearer(ib_ptr->bearer); | ||
| 262 | break; | ||
| 263 | case NETDEV_UP: | ||
| 264 | tipc_continue(ib_ptr->bearer); | ||
| 265 | break; | ||
| 266 | case NETDEV_DOWN: | ||
| 267 | tipc_block_bearer(ib_ptr->bearer); | ||
| 268 | break; | ||
| 269 | case NETDEV_CHANGEMTU: | ||
| 270 | case NETDEV_CHANGEADDR: | ||
| 271 | tipc_block_bearer(ib_ptr->bearer); | ||
| 272 | tipc_continue(ib_ptr->bearer); | ||
| 273 | break; | ||
| 274 | case NETDEV_UNREGISTER: | ||
| 275 | case NETDEV_CHANGENAME: | ||
| 276 | tipc_disable_bearer(ib_ptr->bearer->name); | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | return NOTIFY_OK; | ||
| 280 | } | ||
| 281 | |||
| 282 | static struct notifier_block notifier = { | ||
| 283 | .notifier_call = recv_notification, | ||
| 284 | .priority = 0, | ||
| 285 | }; | ||
| 286 | |||
| 287 | /** | ||
| 288 | * ib_addr2str - convert InfiniBand address to string | ||
| 289 | */ | ||
| 290 | static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | ||
| 291 | { | 48 | { |
| 292 | if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */ | 49 | if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */ |
| 293 | return 1; | 50 | return 1; |
| @@ -297,10 +54,8 @@ static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) | |||
| 297 | return 0; | 54 | return 0; |
| 298 | } | 55 | } |
| 299 | 56 | ||
| 300 | /** | 57 | /* convert InfiniBand address format to message header format */ |
| 301 | * ib_addr2msg - convert InfiniBand address format to message header format | 58 | static int tipc_ib_addr2msg(struct tipc_media_addr *a, char *msg_area) |
| 302 | */ | ||
| 303 | static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area) | ||
| 304 | { | 59 | { |
| 305 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); | 60 | memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE); |
| 306 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB; | 61 | msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB; |
| @@ -308,65 +63,27 @@ static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area) | |||
| 308 | return 0; | 63 | return 0; |
| 309 | } | 64 | } |
| 310 | 65 | ||
| 311 | /** | 66 | /* convert message header address format to InfiniBand format */ |
| 312 | * ib_msg2addr - convert message header address format to InfiniBand format | 67 | static int tipc_ib_msg2addr(const struct tipc_bearer *tb_ptr, |
| 313 | */ | 68 | struct tipc_media_addr *a, char *msg_area) |
| 314 | static int ib_msg2addr(const struct tipc_bearer *tb_ptr, | ||
| 315 | struct tipc_media_addr *a, char *msg_area) | ||
| 316 | { | 69 | { |
| 317 | ib_media_addr_set(tb_ptr, a, msg_area); | 70 | tipc_l2_media_addr_set(tb_ptr, a, msg_area); |
| 318 | return 0; | 71 | return 0; |
| 319 | } | 72 | } |
| 320 | 73 | ||
| 321 | /* | 74 | /* InfiniBand media registration info */ |
| 322 | * InfiniBand media registration info | 75 | struct tipc_media ib_media_info = { |
| 323 | */ | 76 | .send_msg = tipc_l2_send_msg, |
| 324 | static struct tipc_media ib_media_info = { | 77 | .enable_media = tipc_enable_l2_media, |
| 325 | .send_msg = send_msg, | 78 | .disable_media = tipc_disable_l2_media, |
| 326 | .enable_media = enable_media, | 79 | .addr2str = tipc_ib_addr2str, |
| 327 | .disable_media = disable_media, | 80 | .addr2msg = tipc_ib_addr2msg, |
| 328 | .addr2str = ib_addr2str, | 81 | .msg2addr = tipc_ib_msg2addr, |
| 329 | .addr2msg = ib_addr2msg, | ||
| 330 | .msg2addr = ib_msg2addr, | ||
| 331 | .priority = TIPC_DEF_LINK_PRI, | 82 | .priority = TIPC_DEF_LINK_PRI, |
| 332 | .tolerance = TIPC_DEF_LINK_TOL, | 83 | .tolerance = TIPC_DEF_LINK_TOL, |
| 333 | .window = TIPC_DEF_LINK_WIN, | 84 | .window = TIPC_DEF_LINK_WIN, |
| 334 | .type_id = TIPC_MEDIA_TYPE_IB, | 85 | .type_id = TIPC_MEDIA_TYPE_IB, |
| 86 | .hwaddr_len = INFINIBAND_ALEN, | ||
| 335 | .name = "ib" | 87 | .name = "ib" |
| 336 | }; | 88 | }; |
| 337 | 89 | ||
| 338 | /** | ||
| 339 | * tipc_ib_media_start - activate InfiniBand bearer support | ||
| 340 | * | ||
| 341 | * Register InfiniBand media type with TIPC bearer code. Also register | ||
| 342 | * with OS for notifications about device state changes. | ||
| 343 | */ | ||
| 344 | int tipc_ib_media_start(void) | ||
| 345 | { | ||
| 346 | int res; | ||
| 347 | |||
| 348 | if (ib_started) | ||
| 349 | return -EINVAL; | ||
| 350 | |||
| 351 | res = tipc_register_media(&ib_media_info); | ||
| 352 | if (res) | ||
| 353 | return res; | ||
| 354 | |||
| 355 | res = register_netdevice_notifier(¬ifier); | ||
| 356 | if (!res) | ||
| 357 | ib_started = 1; | ||
| 358 | return res; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * tipc_ib_media_stop - deactivate InfiniBand bearer support | ||
| 363 | */ | ||
| 364 | void tipc_ib_media_stop(void) | ||
| 365 | { | ||
| 366 | if (!ib_started) | ||
| 367 | return; | ||
| 368 | |||
| 369 | flush_scheduled_work(); | ||
| 370 | unregister_netdevice_notifier(¬ifier); | ||
| 371 | ib_started = 0; | ||
| 372 | } | ||
diff --git a/net/tipc/link.c b/net/tipc/link.c index 69cd9bf3f561..da6018beb6eb 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/link.c: TIPC link code | 2 | * net/tipc/link.c: TIPC link code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1996-2007, 2012, Ericsson AB | 4 | * Copyright (c) 1996-2007, 2012-2014, Ericsson AB |
| 5 | * Copyright (c) 2004-2007, 2010-2013, Wind River Systems | 5 | * Copyright (c) 2004-2007, 2010-2013, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -78,8 +78,8 @@ static const char *link_unk_evt = "Unknown link event "; | |||
| 78 | static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, | 78 | static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, |
| 79 | struct sk_buff *buf); | 79 | struct sk_buff *buf); |
| 80 | static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf); | 80 | static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf); |
| 81 | static int link_recv_changeover_msg(struct tipc_link **l_ptr, | 81 | static int tipc_link_tunnel_rcv(struct tipc_link **l_ptr, |
| 82 | struct sk_buff **buf); | 82 | struct sk_buff **buf); |
| 83 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); | 83 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); |
| 84 | static int link_send_sections_long(struct tipc_port *sender, | 84 | static int link_send_sections_long(struct tipc_port *sender, |
| 85 | struct iovec const *msg_sect, | 85 | struct iovec const *msg_sect, |
| @@ -87,7 +87,6 @@ static int link_send_sections_long(struct tipc_port *sender, | |||
| 87 | static void link_state_event(struct tipc_link *l_ptr, u32 event); | 87 | static void link_state_event(struct tipc_link *l_ptr, u32 event); |
| 88 | static void link_reset_statistics(struct tipc_link *l_ptr); | 88 | static void link_reset_statistics(struct tipc_link *l_ptr); |
| 89 | static void link_print(struct tipc_link *l_ptr, const char *str); | 89 | static void link_print(struct tipc_link *l_ptr, const char *str); |
| 90 | static void link_start(struct tipc_link *l_ptr); | ||
| 91 | static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf); | 90 | static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf); |
| 92 | static void tipc_link_send_sync(struct tipc_link *l); | 91 | static void tipc_link_send_sync(struct tipc_link *l); |
| 93 | static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf); | 92 | static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf); |
| @@ -278,9 +277,11 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
| 278 | 277 | ||
| 279 | tipc_node_attach_link(n_ptr, l_ptr); | 278 | tipc_node_attach_link(n_ptr, l_ptr); |
| 280 | 279 | ||
| 281 | k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr); | 280 | k_init_timer(&l_ptr->timer, (Handler)link_timeout, |
| 281 | (unsigned long)l_ptr); | ||
| 282 | list_add_tail(&l_ptr->link_list, &b_ptr->links); | 282 | list_add_tail(&l_ptr->link_list, &b_ptr->links); |
| 283 | tipc_k_signal((Handler)link_start, (unsigned long)l_ptr); | 283 | |
| 284 | link_state_event(l_ptr, STARTING_EVT); | ||
| 284 | 285 | ||
| 285 | return l_ptr; | 286 | return l_ptr; |
| 286 | } | 287 | } |
| @@ -305,19 +306,13 @@ void tipc_link_delete(struct tipc_link *l_ptr) | |||
| 305 | tipc_node_lock(l_ptr->owner); | 306 | tipc_node_lock(l_ptr->owner); |
| 306 | tipc_link_reset(l_ptr); | 307 | tipc_link_reset(l_ptr); |
| 307 | tipc_node_detach_link(l_ptr->owner, l_ptr); | 308 | tipc_node_detach_link(l_ptr->owner, l_ptr); |
| 308 | tipc_link_stop(l_ptr); | 309 | tipc_link_purge_queues(l_ptr); |
| 309 | list_del_init(&l_ptr->link_list); | 310 | list_del_init(&l_ptr->link_list); |
| 310 | tipc_node_unlock(l_ptr->owner); | 311 | tipc_node_unlock(l_ptr->owner); |
| 311 | k_term_timer(&l_ptr->timer); | 312 | k_term_timer(&l_ptr->timer); |
| 312 | kfree(l_ptr); | 313 | kfree(l_ptr); |
| 313 | } | 314 | } |
| 314 | 315 | ||
| 315 | static void link_start(struct tipc_link *l_ptr) | ||
| 316 | { | ||
| 317 | tipc_node_lock(l_ptr->owner); | ||
| 318 | link_state_event(l_ptr, STARTING_EVT); | ||
| 319 | tipc_node_unlock(l_ptr->owner); | ||
| 320 | } | ||
| 321 | 316 | ||
| 322 | /** | 317 | /** |
| 323 | * link_schedule_port - schedule port for deferred sending | 318 | * link_schedule_port - schedule port for deferred sending |
| @@ -386,14 +381,7 @@ exit: | |||
| 386 | */ | 381 | */ |
| 387 | static void link_release_outqueue(struct tipc_link *l_ptr) | 382 | static void link_release_outqueue(struct tipc_link *l_ptr) |
| 388 | { | 383 | { |
| 389 | struct sk_buff *buf = l_ptr->first_out; | 384 | kfree_skb_list(l_ptr->first_out); |
| 390 | struct sk_buff *next; | ||
| 391 | |||
| 392 | while (buf) { | ||
| 393 | next = buf->next; | ||
| 394 | kfree_skb(buf); | ||
| 395 | buf = next; | ||
| 396 | } | ||
| 397 | l_ptr->first_out = NULL; | 385 | l_ptr->first_out = NULL; |
| 398 | l_ptr->out_queue_size = 0; | 386 | l_ptr->out_queue_size = 0; |
| 399 | } | 387 | } |
| @@ -410,37 +398,20 @@ void tipc_link_reset_fragments(struct tipc_link *l_ptr) | |||
| 410 | } | 398 | } |
| 411 | 399 | ||
| 412 | /** | 400 | /** |
| 413 | * tipc_link_stop - purge all inbound and outbound messages associated with link | 401 | * tipc_link_purge_queues - purge all pkt queues associated with link |
| 414 | * @l_ptr: pointer to link | 402 | * @l_ptr: pointer to link |
| 415 | */ | 403 | */ |
| 416 | void tipc_link_stop(struct tipc_link *l_ptr) | 404 | void tipc_link_purge_queues(struct tipc_link *l_ptr) |
| 417 | { | 405 | { |
| 418 | struct sk_buff *buf; | 406 | kfree_skb_list(l_ptr->oldest_deferred_in); |
| 419 | struct sk_buff *next; | 407 | kfree_skb_list(l_ptr->first_out); |
| 420 | |||
| 421 | buf = l_ptr->oldest_deferred_in; | ||
| 422 | while (buf) { | ||
| 423 | next = buf->next; | ||
| 424 | kfree_skb(buf); | ||
| 425 | buf = next; | ||
| 426 | } | ||
| 427 | |||
| 428 | buf = l_ptr->first_out; | ||
| 429 | while (buf) { | ||
| 430 | next = buf->next; | ||
| 431 | kfree_skb(buf); | ||
| 432 | buf = next; | ||
| 433 | } | ||
| 434 | |||
| 435 | tipc_link_reset_fragments(l_ptr); | 408 | tipc_link_reset_fragments(l_ptr); |
| 436 | |||
| 437 | kfree_skb(l_ptr->proto_msg_queue); | 409 | kfree_skb(l_ptr->proto_msg_queue); |
| 438 | l_ptr->proto_msg_queue = NULL; | 410 | l_ptr->proto_msg_queue = NULL; |
| 439 | } | 411 | } |
| 440 | 412 | ||
| 441 | void tipc_link_reset(struct tipc_link *l_ptr) | 413 | void tipc_link_reset(struct tipc_link *l_ptr) |
| 442 | { | 414 | { |
| 443 | struct sk_buff *buf; | ||
| 444 | u32 prev_state = l_ptr->state; | 415 | u32 prev_state = l_ptr->state; |
| 445 | u32 checkpoint = l_ptr->next_in_no; | 416 | u32 checkpoint = l_ptr->next_in_no; |
| 446 | int was_active_link = tipc_link_is_active(l_ptr); | 417 | int was_active_link = tipc_link_is_active(l_ptr); |
| @@ -461,8 +432,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
| 461 | tipc_node_link_down(l_ptr->owner, l_ptr); | 432 | tipc_node_link_down(l_ptr->owner, l_ptr); |
| 462 | tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr); | 433 | tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr); |
| 463 | 434 | ||
| 464 | if (was_active_link && tipc_node_active_links(l_ptr->owner) && | 435 | if (was_active_link && tipc_node_active_links(l_ptr->owner)) { |
| 465 | l_ptr->owner->permit_changeover) { | ||
| 466 | l_ptr->reset_checkpoint = checkpoint; | 436 | l_ptr->reset_checkpoint = checkpoint; |
| 467 | l_ptr->exp_msg_count = START_CHANGEOVER; | 437 | l_ptr->exp_msg_count = START_CHANGEOVER; |
| 468 | } | 438 | } |
| @@ -471,12 +441,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
| 471 | link_release_outqueue(l_ptr); | 441 | link_release_outqueue(l_ptr); |
| 472 | kfree_skb(l_ptr->proto_msg_queue); | 442 | kfree_skb(l_ptr->proto_msg_queue); |
| 473 | l_ptr->proto_msg_queue = NULL; | 443 | l_ptr->proto_msg_queue = NULL; |
| 474 | buf = l_ptr->oldest_deferred_in; | 444 | kfree_skb_list(l_ptr->oldest_deferred_in); |
| 475 | while (buf) { | ||
| 476 | struct sk_buff *next = buf->next; | ||
| 477 | kfree_skb(buf); | ||
| 478 | buf = next; | ||
| 479 | } | ||
| 480 | if (!list_empty(&l_ptr->waiting_ports)) | 445 | if (!list_empty(&l_ptr->waiting_ports)) |
| 481 | tipc_link_wakeup_ports(l_ptr, 1); | 446 | tipc_link_wakeup_ports(l_ptr, 1); |
| 482 | 447 | ||
| @@ -517,10 +482,11 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) | |||
| 517 | if (!l_ptr->started && (event != STARTING_EVT)) | 482 | if (!l_ptr->started && (event != STARTING_EVT)) |
| 518 | return; /* Not yet. */ | 483 | return; /* Not yet. */ |
| 519 | 484 | ||
| 520 | if (link_blocked(l_ptr)) { | 485 | /* Check whether changeover is going on */ |
| 486 | if (l_ptr->exp_msg_count) { | ||
| 521 | if (event == TIMEOUT_EVT) | 487 | if (event == TIMEOUT_EVT) |
| 522 | link_set_timer(l_ptr, cont_intv); | 488 | link_set_timer(l_ptr, cont_intv); |
| 523 | return; /* Changeover going on */ | 489 | return; |
| 524 | } | 490 | } |
| 525 | 491 | ||
| 526 | switch (l_ptr->state) { | 492 | switch (l_ptr->state) { |
| @@ -790,8 +756,7 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 790 | return link_send_long_buf(l_ptr, buf); | 756 | return link_send_long_buf(l_ptr, buf); |
| 791 | 757 | ||
| 792 | /* Packet can be queued or sent. */ | 758 | /* Packet can be queued or sent. */ |
| 793 | if (likely(!tipc_bearer_blocked(l_ptr->b_ptr) && | 759 | if (likely(!link_congested(l_ptr))) { |
| 794 | !link_congested(l_ptr))) { | ||
| 795 | link_add_to_outqueue(l_ptr, buf, msg); | 760 | link_add_to_outqueue(l_ptr, buf, msg); |
| 796 | 761 | ||
| 797 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); | 762 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); |
| @@ -957,14 +922,13 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
| 957 | 922 | ||
| 958 | if (likely(!link_congested(l_ptr))) { | 923 | if (likely(!link_congested(l_ptr))) { |
| 959 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { | 924 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { |
| 960 | if (likely(!tipc_bearer_blocked(l_ptr->b_ptr))) { | 925 | link_add_to_outqueue(l_ptr, buf, msg); |
| 961 | link_add_to_outqueue(l_ptr, buf, msg); | 926 | tipc_bearer_send(l_ptr->b_ptr, buf, |
| 962 | tipc_bearer_send(l_ptr->b_ptr, buf, | 927 | &l_ptr->media_addr); |
| 963 | &l_ptr->media_addr); | 928 | l_ptr->unacked_window = 0; |
| 964 | l_ptr->unacked_window = 0; | 929 | return res; |
| 965 | return res; | 930 | } |
| 966 | } | 931 | else |
| 967 | } else | ||
| 968 | *used_max_pkt = l_ptr->max_pkt; | 932 | *used_max_pkt = l_ptr->max_pkt; |
| 969 | } | 933 | } |
| 970 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ | 934 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ |
| @@ -1013,8 +977,7 @@ exit: | |||
| 1013 | } | 977 | } |
| 1014 | 978 | ||
| 1015 | /* Exit if link (or bearer) is congested */ | 979 | /* Exit if link (or bearer) is congested */ |
| 1016 | if (link_congested(l_ptr) || | 980 | if (link_congested(l_ptr)) { |
| 1017 | tipc_bearer_blocked(l_ptr->b_ptr)) { | ||
| 1018 | res = link_schedule_port(l_ptr, | 981 | res = link_schedule_port(l_ptr, |
| 1019 | sender->ref, res); | 982 | sender->ref, res); |
| 1020 | goto exit; | 983 | goto exit; |
| @@ -1127,10 +1090,7 @@ again: | |||
| 1127 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { | 1090 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { |
| 1128 | res = -EFAULT; | 1091 | res = -EFAULT; |
| 1129 | error: | 1092 | error: |
| 1130 | for (; buf_chain; buf_chain = buf) { | 1093 | kfree_skb_list(buf_chain); |
| 1131 | buf = buf_chain->next; | ||
| 1132 | kfree_skb(buf_chain); | ||
| 1133 | } | ||
| 1134 | return res; | 1094 | return res; |
| 1135 | } | 1095 | } |
| 1136 | sect_crs += sz; | 1096 | sect_crs += sz; |
| @@ -1180,18 +1140,12 @@ error: | |||
| 1180 | if (l_ptr->max_pkt < max_pkt) { | 1140 | if (l_ptr->max_pkt < max_pkt) { |
| 1181 | sender->max_pkt = l_ptr->max_pkt; | 1141 | sender->max_pkt = l_ptr->max_pkt; |
| 1182 | tipc_node_unlock(node); | 1142 | tipc_node_unlock(node); |
| 1183 | for (; buf_chain; buf_chain = buf) { | 1143 | kfree_skb_list(buf_chain); |
| 1184 | buf = buf_chain->next; | ||
| 1185 | kfree_skb(buf_chain); | ||
| 1186 | } | ||
| 1187 | goto again; | 1144 | goto again; |
| 1188 | } | 1145 | } |
| 1189 | } else { | 1146 | } else { |
| 1190 | reject: | 1147 | reject: |
| 1191 | for (; buf_chain; buf_chain = buf) { | 1148 | kfree_skb_list(buf_chain); |
| 1192 | buf = buf_chain->next; | ||
| 1193 | kfree_skb(buf_chain); | ||
| 1194 | } | ||
| 1195 | return tipc_port_reject_sections(sender, hdr, msg_sect, | 1149 | return tipc_port_reject_sections(sender, hdr, msg_sect, |
| 1196 | len, TIPC_ERR_NO_NODE); | 1150 | len, TIPC_ERR_NO_NODE); |
| 1197 | } | 1151 | } |
| @@ -1209,7 +1163,7 @@ reject: | |||
| 1209 | /* | 1163 | /* |
| 1210 | * tipc_link_push_packet: Push one unsent packet to the media | 1164 | * tipc_link_push_packet: Push one unsent packet to the media |
| 1211 | */ | 1165 | */ |
| 1212 | u32 tipc_link_push_packet(struct tipc_link *l_ptr) | 1166 | static u32 tipc_link_push_packet(struct tipc_link *l_ptr) |
| 1213 | { | 1167 | { |
| 1214 | struct sk_buff *buf = l_ptr->first_out; | 1168 | struct sk_buff *buf = l_ptr->first_out; |
| 1215 | u32 r_q_size = l_ptr->retransm_queue_size; | 1169 | u32 r_q_size = l_ptr->retransm_queue_size; |
| @@ -1281,9 +1235,6 @@ void tipc_link_push_queue(struct tipc_link *l_ptr) | |||
| 1281 | { | 1235 | { |
| 1282 | u32 res; | 1236 | u32 res; |
| 1283 | 1237 | ||
| 1284 | if (tipc_bearer_blocked(l_ptr->b_ptr)) | ||
| 1285 | return; | ||
| 1286 | |||
| 1287 | do { | 1238 | do { |
| 1288 | res = tipc_link_push_packet(l_ptr); | 1239 | res = tipc_link_push_packet(l_ptr); |
| 1289 | } while (!res); | 1240 | } while (!res); |
| @@ -1370,26 +1321,15 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
| 1370 | 1321 | ||
| 1371 | msg = buf_msg(buf); | 1322 | msg = buf_msg(buf); |
| 1372 | 1323 | ||
| 1373 | if (tipc_bearer_blocked(l_ptr->b_ptr)) { | 1324 | /* Detect repeated retransmit failures */ |
| 1374 | if (l_ptr->retransm_queue_size == 0) { | 1325 | if (l_ptr->last_retransmitted == msg_seqno(msg)) { |
| 1375 | l_ptr->retransm_queue_head = msg_seqno(msg); | 1326 | if (++l_ptr->stale_count > 100) { |
| 1376 | l_ptr->retransm_queue_size = retransmits; | 1327 | link_retransmit_failure(l_ptr, buf); |
| 1377 | } else { | 1328 | return; |
| 1378 | pr_err("Unexpected retransmit on link %s (qsize=%d)\n", | ||
| 1379 | l_ptr->name, l_ptr->retransm_queue_size); | ||
| 1380 | } | 1329 | } |
| 1381 | return; | ||
| 1382 | } else { | 1330 | } else { |
| 1383 | /* Detect repeated retransmit failures on unblocked bearer */ | 1331 | l_ptr->last_retransmitted = msg_seqno(msg); |
| 1384 | if (l_ptr->last_retransmitted == msg_seqno(msg)) { | 1332 | l_ptr->stale_count = 1; |
| 1385 | if (++l_ptr->stale_count > 100) { | ||
| 1386 | link_retransmit_failure(l_ptr, buf); | ||
| 1387 | return; | ||
| 1388 | } | ||
| 1389 | } else { | ||
| 1390 | l_ptr->last_retransmitted = msg_seqno(msg); | ||
| 1391 | l_ptr->stale_count = 1; | ||
| 1392 | } | ||
| 1393 | } | 1333 | } |
| 1394 | 1334 | ||
| 1395 | while (retransmits && (buf != l_ptr->next_out) && buf) { | 1335 | while (retransmits && (buf != l_ptr->next_out) && buf) { |
| @@ -1451,6 +1391,12 @@ static int link_recv_buf_validate(struct sk_buff *buf) | |||
| 1451 | u32 hdr_size; | 1391 | u32 hdr_size; |
| 1452 | u32 min_hdr_size; | 1392 | u32 min_hdr_size; |
| 1453 | 1393 | ||
| 1394 | /* If this packet comes from the defer queue, the skb has already | ||
| 1395 | * been validated | ||
| 1396 | */ | ||
| 1397 | if (unlikely(TIPC_SKB_CB(buf)->deferred)) | ||
| 1398 | return 1; | ||
| 1399 | |||
| 1454 | if (unlikely(buf->len < MIN_H_SIZE)) | 1400 | if (unlikely(buf->len < MIN_H_SIZE)) |
| 1455 | return 0; | 1401 | return 0; |
| 1456 | 1402 | ||
| @@ -1476,14 +1422,14 @@ static int link_recv_buf_validate(struct sk_buff *buf) | |||
| 1476 | } | 1422 | } |
| 1477 | 1423 | ||
| 1478 | /** | 1424 | /** |
| 1479 | * tipc_recv_msg - process TIPC messages arriving from off-node | 1425 | * tipc_rcv - process TIPC packets/messages arriving from off-node |
| 1480 | * @head: pointer to message buffer chain | 1426 | * @head: pointer to message buffer chain |
| 1481 | * @tb_ptr: pointer to bearer message arrived on | 1427 | * @tb_ptr: pointer to bearer message arrived on |
| 1482 | * | 1428 | * |
| 1483 | * Invoked with no locks held. Bearer pointer must point to a valid bearer | 1429 | * Invoked with no locks held. Bearer pointer must point to a valid bearer |
| 1484 | * structure (i.e. cannot be NULL), but bearer can be inactive. | 1430 | * structure (i.e. cannot be NULL), but bearer can be inactive. |
| 1485 | */ | 1431 | */ |
| 1486 | void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | 1432 | void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) |
| 1487 | { | 1433 | { |
| 1488 | read_lock_bh(&tipc_net_lock); | 1434 | read_lock_bh(&tipc_net_lock); |
| 1489 | while (head) { | 1435 | while (head) { |
| @@ -1498,6 +1444,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
| 1498 | int type; | 1444 | int type; |
| 1499 | 1445 | ||
| 1500 | head = head->next; | 1446 | head = head->next; |
| 1447 | buf->next = NULL; | ||
| 1501 | 1448 | ||
| 1502 | /* Ensure bearer is still enabled */ | 1449 | /* Ensure bearer is still enabled */ |
| 1503 | if (unlikely(!b_ptr->active)) | 1450 | if (unlikely(!b_ptr->active)) |
| @@ -1657,7 +1604,7 @@ deliver: | |||
| 1657 | continue; | 1604 | continue; |
| 1658 | case CHANGEOVER_PROTOCOL: | 1605 | case CHANGEOVER_PROTOCOL: |
| 1659 | type = msg_type(msg); | 1606 | type = msg_type(msg); |
| 1660 | if (link_recv_changeover_msg(&l_ptr, &buf)) { | 1607 | if (tipc_link_tunnel_rcv(&l_ptr, &buf)) { |
| 1661 | msg = buf_msg(buf); | 1608 | msg = buf_msg(buf); |
| 1662 | seq_no = msg_seqno(msg); | 1609 | seq_no = msg_seqno(msg); |
| 1663 | if (type == ORIGINAL_MSG) | 1610 | if (type == ORIGINAL_MSG) |
| @@ -1762,6 +1709,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, | |||
| 1762 | &l_ptr->newest_deferred_in, buf)) { | 1709 | &l_ptr->newest_deferred_in, buf)) { |
| 1763 | l_ptr->deferred_inqueue_sz++; | 1710 | l_ptr->deferred_inqueue_sz++; |
| 1764 | l_ptr->stats.deferred_recv++; | 1711 | l_ptr->stats.deferred_recv++; |
| 1712 | TIPC_SKB_CB(buf)->deferred = true; | ||
| 1765 | if ((l_ptr->deferred_inqueue_sz % 16) == 1) | 1713 | if ((l_ptr->deferred_inqueue_sz % 16) == 1) |
| 1766 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); | 1714 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); |
| 1767 | } else | 1715 | } else |
| @@ -1786,7 +1734,8 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, | |||
| 1786 | l_ptr->proto_msg_queue = NULL; | 1734 | l_ptr->proto_msg_queue = NULL; |
| 1787 | } | 1735 | } |
| 1788 | 1736 | ||
| 1789 | if (link_blocked(l_ptr)) | 1737 | /* Don't send protocol message during link changeover */ |
| 1738 | if (l_ptr->exp_msg_count) | ||
| 1790 | return; | 1739 | return; |
| 1791 | 1740 | ||
| 1792 | /* Abort non-RESET send if communication with node is prohibited */ | 1741 | /* Abort non-RESET send if communication with node is prohibited */ |
| @@ -1861,12 +1810,6 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, | |||
| 1861 | skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); | 1810 | skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); |
| 1862 | buf->priority = TC_PRIO_CONTROL; | 1811 | buf->priority = TC_PRIO_CONTROL; |
| 1863 | 1812 | ||
| 1864 | /* Defer message if bearer is already blocked */ | ||
| 1865 | if (tipc_bearer_blocked(l_ptr->b_ptr)) { | ||
| 1866 | l_ptr->proto_msg_queue = buf; | ||
| 1867 | return; | ||
| 1868 | } | ||
| 1869 | |||
| 1870 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); | 1813 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); |
| 1871 | l_ptr->unacked_window = 0; | 1814 | l_ptr->unacked_window = 0; |
| 1872 | kfree_skb(buf); | 1815 | kfree_skb(buf); |
| @@ -1885,7 +1828,8 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 1885 | u32 msg_tol; | 1828 | u32 msg_tol; |
| 1886 | struct tipc_msg *msg = buf_msg(buf); | 1829 | struct tipc_msg *msg = buf_msg(buf); |
| 1887 | 1830 | ||
| 1888 | if (link_blocked(l_ptr)) | 1831 | /* Discard protocol message during link changeover */ |
| 1832 | if (l_ptr->exp_msg_count) | ||
| 1889 | goto exit; | 1833 | goto exit; |
| 1890 | 1834 | ||
| 1891 | /* record unnumbered packet arrival (force mismatch on next timeout) */ | 1835 | /* record unnumbered packet arrival (force mismatch on next timeout) */ |
| @@ -1895,8 +1839,6 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 1895 | if (tipc_own_addr > msg_prevnode(msg)) | 1839 | if (tipc_own_addr > msg_prevnode(msg)) |
| 1896 | l_ptr->b_ptr->net_plane = msg_net_plane(msg); | 1840 | l_ptr->b_ptr->net_plane = msg_net_plane(msg); |
| 1897 | 1841 | ||
| 1898 | l_ptr->owner->permit_changeover = msg_redundant_link(msg); | ||
| 1899 | |||
| 1900 | switch (msg_type(msg)) { | 1842 | switch (msg_type(msg)) { |
| 1901 | 1843 | ||
| 1902 | case RESET_MSG: | 1844 | case RESET_MSG: |
| @@ -2012,13 +1954,13 @@ exit: | |||
| 2012 | } | 1954 | } |
| 2013 | 1955 | ||
| 2014 | 1956 | ||
| 2015 | /* | 1957 | /* tipc_link_tunnel_xmit(): Tunnel one packet via a link belonging to |
| 2016 | * tipc_link_tunnel(): Send one message via a link belonging to | 1958 | * a different bearer. Owner node is locked. |
| 2017 | * another bearer. Owner node is locked. | ||
| 2018 | */ | 1959 | */ |
| 2019 | static void tipc_link_tunnel(struct tipc_link *l_ptr, | 1960 | static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr, |
| 2020 | struct tipc_msg *tunnel_hdr, struct tipc_msg *msg, | 1961 | struct tipc_msg *tunnel_hdr, |
| 2021 | u32 selector) | 1962 | struct tipc_msg *msg, |
| 1963 | u32 selector) | ||
| 2022 | { | 1964 | { |
| 2023 | struct tipc_link *tunnel; | 1965 | struct tipc_link *tunnel; |
| 2024 | struct sk_buff *buf; | 1966 | struct sk_buff *buf; |
| @@ -2041,12 +1983,13 @@ static void tipc_link_tunnel(struct tipc_link *l_ptr, | |||
| 2041 | } | 1983 | } |
| 2042 | 1984 | ||
| 2043 | 1985 | ||
| 2044 | 1986 | /* tipc_link_failover_send_queue(): A link has gone down, but a second | |
| 2045 | /* | 1987 | * link is still active. We can do failover. Tunnel the failing link's |
| 2046 | * changeover(): Send whole message queue via the remaining link | 1988 | * whole send queue via the remaining link. This way, we don't lose |
| 2047 | * Owner node is locked. | 1989 | * any packets, and sequence order is preserved for subsequent traffic |
| 1990 | * sent over the remaining link. Owner node is locked. | ||
| 2048 | */ | 1991 | */ |
| 2049 | void tipc_link_changeover(struct tipc_link *l_ptr) | 1992 | void tipc_link_failover_send_queue(struct tipc_link *l_ptr) |
| 2050 | { | 1993 | { |
| 2051 | u32 msgcount = l_ptr->out_queue_size; | 1994 | u32 msgcount = l_ptr->out_queue_size; |
| 2052 | struct sk_buff *crs = l_ptr->first_out; | 1995 | struct sk_buff *crs = l_ptr->first_out; |
| @@ -2057,11 +2000,6 @@ void tipc_link_changeover(struct tipc_link *l_ptr) | |||
| 2057 | if (!tunnel) | 2000 | if (!tunnel) |
| 2058 | return; | 2001 | return; |
| 2059 | 2002 | ||
| 2060 | if (!l_ptr->owner->permit_changeover) { | ||
| 2061 | pr_warn("%speer did not permit changeover\n", link_co_err); | ||
| 2062 | return; | ||
| 2063 | } | ||
| 2064 | |||
| 2065 | tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, | 2003 | tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, |
| 2066 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); | 2004 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); |
| 2067 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); | 2005 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); |
| @@ -2095,20 +2033,30 @@ void tipc_link_changeover(struct tipc_link *l_ptr) | |||
| 2095 | msgcount = msg_msgcnt(msg); | 2033 | msgcount = msg_msgcnt(msg); |
| 2096 | while (msgcount--) { | 2034 | while (msgcount--) { |
| 2097 | msg_set_seqno(m, msg_seqno(msg)); | 2035 | msg_set_seqno(m, msg_seqno(msg)); |
| 2098 | tipc_link_tunnel(l_ptr, &tunnel_hdr, m, | 2036 | tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, m, |
| 2099 | msg_link_selector(m)); | 2037 | msg_link_selector(m)); |
| 2100 | pos += align(msg_size(m)); | 2038 | pos += align(msg_size(m)); |
| 2101 | m = (struct tipc_msg *)pos; | 2039 | m = (struct tipc_msg *)pos; |
| 2102 | } | 2040 | } |
| 2103 | } else { | 2041 | } else { |
| 2104 | tipc_link_tunnel(l_ptr, &tunnel_hdr, msg, | 2042 | tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, msg, |
| 2105 | msg_link_selector(msg)); | 2043 | msg_link_selector(msg)); |
| 2106 | } | 2044 | } |
| 2107 | crs = crs->next; | 2045 | crs = crs->next; |
| 2108 | } | 2046 | } |
| 2109 | } | 2047 | } |
| 2110 | 2048 | ||
| 2111 | void tipc_link_send_duplicate(struct tipc_link *l_ptr, struct tipc_link *tunnel) | 2049 | /* tipc_link_dup_send_queue(): A second link has become active. Tunnel a |
| 2050 | * duplicate of the first link's send queue via the new link. This way, we | ||
| 2051 | * are guaranteed that currently queued packets from a socket are delivered | ||
| 2052 | * before future traffic from the same socket, even if this is using the | ||
| 2053 | * new link. The last arriving copy of each duplicate packet is dropped at | ||
| 2054 | * the receiving end by the regular protocol check, so packet cardinality | ||
| 2055 | * and sequence order is preserved per sender/receiver socket pair. | ||
| 2056 | * Owner node is locked. | ||
| 2057 | */ | ||
| 2058 | void tipc_link_dup_send_queue(struct tipc_link *l_ptr, | ||
| 2059 | struct tipc_link *tunnel) | ||
| 2112 | { | 2060 | { |
| 2113 | struct sk_buff *iter; | 2061 | struct sk_buff *iter; |
| 2114 | struct tipc_msg tunnel_hdr; | 2062 | struct tipc_msg tunnel_hdr; |
| @@ -2164,12 +2112,14 @@ static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos) | |||
| 2164 | return eb; | 2112 | return eb; |
| 2165 | } | 2113 | } |
| 2166 | 2114 | ||
| 2167 | /* | 2115 | /* tipc_link_tunnel_rcv(): Receive a tunneled packet, sent |
| 2168 | * link_recv_changeover_msg(): Receive tunneled packet sent | 2116 | * via other link as result of a failover (ORIGINAL_MSG) or |
| 2169 | * via other link. Node is locked. Return extracted buffer. | 2117 | * a new active link (DUPLICATE_MSG). Failover packets are |
| 2118 | * returned to the active link for delivery upwards. | ||
| 2119 | * Owner node is locked. | ||
| 2170 | */ | 2120 | */ |
| 2171 | static int link_recv_changeover_msg(struct tipc_link **l_ptr, | 2121 | static int tipc_link_tunnel_rcv(struct tipc_link **l_ptr, |
| 2172 | struct sk_buff **buf) | 2122 | struct sk_buff **buf) |
| 2173 | { | 2123 | { |
| 2174 | struct sk_buff *tunnel_buf = *buf; | 2124 | struct sk_buff *tunnel_buf = *buf; |
| 2175 | struct tipc_link *dest_link; | 2125 | struct tipc_link *dest_link; |
| @@ -2306,11 +2256,7 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
| 2306 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | 2256 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); |
| 2307 | if (fragm == NULL) { | 2257 | if (fragm == NULL) { |
| 2308 | kfree_skb(buf); | 2258 | kfree_skb(buf); |
| 2309 | while (buf_chain) { | 2259 | kfree_skb_list(buf_chain); |
| 2310 | buf = buf_chain; | ||
| 2311 | buf_chain = buf_chain->next; | ||
| 2312 | kfree_skb(buf); | ||
| 2313 | } | ||
| 2314 | return -ENOMEM; | 2260 | return -ENOMEM; |
| 2315 | } | 2261 | } |
| 2316 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | 2262 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); |
diff --git a/net/tipc/link.h b/net/tipc/link.h index 8a6c1026644d..3b6aa65b608c 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
| @@ -112,7 +112,6 @@ struct tipc_stats { | |||
| 112 | * @continuity_interval: link continuity testing interval [in ms] | 112 | * @continuity_interval: link continuity testing interval [in ms] |
| 113 | * @abort_limit: # of unacknowledged continuity probes needed to reset link | 113 | * @abort_limit: # of unacknowledged continuity probes needed to reset link |
| 114 | * @state: current state of link FSM | 114 | * @state: current state of link FSM |
| 115 | * @blocked: indicates if link has been administratively blocked | ||
| 116 | * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state | 115 | * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state |
| 117 | * @proto_msg: template for control messages generated by link | 116 | * @proto_msg: template for control messages generated by link |
| 118 | * @pmsg: convenience pointer to "proto_msg" field | 117 | * @pmsg: convenience pointer to "proto_msg" field |
| @@ -162,7 +161,6 @@ struct tipc_link { | |||
| 162 | u32 continuity_interval; | 161 | u32 continuity_interval; |
| 163 | u32 abort_limit; | 162 | u32 abort_limit; |
| 164 | int state; | 163 | int state; |
| 165 | int blocked; | ||
| 166 | u32 fsm_msg_cnt; | 164 | u32 fsm_msg_cnt; |
| 167 | struct { | 165 | struct { |
| 168 | unchar hdr[INT_H_SIZE]; | 166 | unchar hdr[INT_H_SIZE]; |
| @@ -218,16 +216,20 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
| 218 | struct tipc_bearer *b_ptr, | 216 | struct tipc_bearer *b_ptr, |
| 219 | const struct tipc_media_addr *media_addr); | 217 | const struct tipc_media_addr *media_addr); |
| 220 | void tipc_link_delete(struct tipc_link *l_ptr); | 218 | void tipc_link_delete(struct tipc_link *l_ptr); |
| 221 | void tipc_link_changeover(struct tipc_link *l_ptr); | 219 | void tipc_link_failover_send_queue(struct tipc_link *l_ptr); |
| 222 | void tipc_link_send_duplicate(struct tipc_link *l_ptr, struct tipc_link *dest); | 220 | void tipc_link_dup_send_queue(struct tipc_link *l_ptr, |
| 221 | struct tipc_link *dest); | ||
| 223 | void tipc_link_reset_fragments(struct tipc_link *l_ptr); | 222 | void tipc_link_reset_fragments(struct tipc_link *l_ptr); |
| 224 | int tipc_link_is_up(struct tipc_link *l_ptr); | 223 | int tipc_link_is_up(struct tipc_link *l_ptr); |
| 225 | int tipc_link_is_active(struct tipc_link *l_ptr); | 224 | int tipc_link_is_active(struct tipc_link *l_ptr); |
| 226 | u32 tipc_link_push_packet(struct tipc_link *l_ptr); | 225 | void tipc_link_purge_queues(struct tipc_link *l_ptr); |
| 227 | void tipc_link_stop(struct tipc_link *l_ptr); | 226 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, |
| 228 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd); | 227 | int req_tlv_space, |
| 229 | struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space); | 228 | u16 cmd); |
| 230 | struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space); | 229 | struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, |
| 230 | int req_tlv_space); | ||
| 231 | struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, | ||
| 232 | int req_tlv_space); | ||
| 231 | void tipc_link_reset(struct tipc_link *l_ptr); | 233 | void tipc_link_reset(struct tipc_link *l_ptr); |
| 232 | int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); | 234 | int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); |
| 233 | void tipc_link_send_names(struct list_head *message_list, u32 dest); | 235 | void tipc_link_send_names(struct list_head *message_list, u32 dest); |
| @@ -312,11 +314,6 @@ static inline int link_reset_reset(struct tipc_link *l_ptr) | |||
| 312 | return l_ptr->state == RESET_RESET; | 314 | return l_ptr->state == RESET_RESET; |
| 313 | } | 315 | } |
| 314 | 316 | ||
| 315 | static inline int link_blocked(struct tipc_link *l_ptr) | ||
| 316 | { | ||
| 317 | return l_ptr->exp_msg_count || l_ptr->blocked; | ||
| 318 | } | ||
| 319 | |||
| 320 | static inline int link_congested(struct tipc_link *l_ptr) | 317 | static inline int link_congested(struct tipc_link *l_ptr) |
| 321 | { | 318 | { |
| 322 | return l_ptr->out_queue_size >= l_ptr->queue_limit[0]; | 319 | return l_ptr->out_queue_size >= l_ptr->queue_limit[0]; |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 09dcd54b04e1..042e8e3cabc0 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c | |||
| @@ -148,8 +148,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, | |||
| 148 | */ | 148 | */ |
| 149 | static struct sub_seq *tipc_subseq_alloc(u32 cnt) | 149 | static struct sub_seq *tipc_subseq_alloc(u32 cnt) |
| 150 | { | 150 | { |
| 151 | struct sub_seq *sseq = kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC); | 151 | return kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC); |
| 152 | return sseq; | ||
| 153 | } | 152 | } |
| 154 | 153 | ||
| 155 | /** | 154 | /** |
| @@ -942,20 +941,48 @@ int tipc_nametbl_init(void) | |||
| 942 | return 0; | 941 | return 0; |
| 943 | } | 942 | } |
| 944 | 943 | ||
| 945 | void tipc_nametbl_stop(void) | 944 | /** |
| 945 | * tipc_purge_publications - remove all publications for a given type | ||
| 946 | * | ||
| 947 | * tipc_nametbl_lock must be held when calling this function | ||
| 948 | */ | ||
| 949 | static void tipc_purge_publications(struct name_seq *seq) | ||
| 946 | { | 950 | { |
| 947 | u32 i; | 951 | struct publication *publ, *safe; |
| 952 | struct sub_seq *sseq; | ||
| 953 | struct name_info *info; | ||
| 948 | 954 | ||
| 949 | if (!table.types) | 955 | if (!seq->sseqs) { |
| 956 | nameseq_delete_empty(seq); | ||
| 950 | return; | 957 | return; |
| 958 | } | ||
| 959 | sseq = seq->sseqs; | ||
| 960 | info = sseq->info; | ||
| 961 | list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) { | ||
| 962 | tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node, | ||
| 963 | publ->ref, publ->key); | ||
| 964 | } | ||
| 965 | } | ||
| 966 | |||
| 967 | void tipc_nametbl_stop(void) | ||
| 968 | { | ||
| 969 | u32 i; | ||
| 970 | struct name_seq *seq; | ||
| 971 | struct hlist_head *seq_head; | ||
| 972 | struct hlist_node *safe; | ||
| 951 | 973 | ||
| 952 | /* Verify name table is empty, then release it */ | 974 | /* Verify name table is empty and purge any lingering |
| 975 | * publications, then release the name table | ||
| 976 | */ | ||
| 953 | write_lock_bh(&tipc_nametbl_lock); | 977 | write_lock_bh(&tipc_nametbl_lock); |
| 954 | for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { | 978 | for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { |
| 955 | if (hlist_empty(&table.types[i])) | 979 | if (hlist_empty(&table.types[i])) |
| 956 | continue; | 980 | continue; |
| 957 | pr_err("nametbl_stop(): orphaned hash chain detected\n"); | 981 | seq_head = &table.types[i]; |
| 958 | break; | 982 | hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) { |
| 983 | tipc_purge_publications(seq); | ||
| 984 | } | ||
| 985 | continue; | ||
| 959 | } | 986 | } |
| 960 | kfree(table.types); | 987 | kfree(table.types); |
| 961 | table.types = NULL; | 988 | table.types = NULL; |
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 9f72a6376362..3aaf73de9e2d 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c | |||
| @@ -83,8 +83,6 @@ static struct genl_ops tipc_genl_ops[] = { | |||
| 83 | }, | 83 | }, |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | static int tipc_genl_family_registered; | ||
| 87 | |||
| 88 | int tipc_netlink_start(void) | 86 | int tipc_netlink_start(void) |
| 89 | { | 87 | { |
| 90 | int res; | 88 | int res; |
| @@ -94,16 +92,10 @@ int tipc_netlink_start(void) | |||
| 94 | pr_err("Failed to register netlink interface\n"); | 92 | pr_err("Failed to register netlink interface\n"); |
| 95 | return res; | 93 | return res; |
| 96 | } | 94 | } |
| 97 | |||
| 98 | tipc_genl_family_registered = 1; | ||
| 99 | return 0; | 95 | return 0; |
| 100 | } | 96 | } |
| 101 | 97 | ||
| 102 | void tipc_netlink_stop(void) | 98 | void tipc_netlink_stop(void) |
| 103 | { | 99 | { |
| 104 | if (!tipc_genl_family_registered) | ||
| 105 | return; | ||
| 106 | |||
| 107 | genl_unregister_family(&tipc_genl_family); | 100 | genl_unregister_family(&tipc_genl_family); |
| 108 | tipc_genl_family_registered = 0; | ||
| 109 | } | 101 | } |
diff --git a/net/tipc/node.c b/net/tipc/node.c index 25100c0a6fe8..efe4d41bf11b 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
| @@ -162,7 +162,7 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 162 | pr_info("New link <%s> becomes standby\n", l_ptr->name); | 162 | pr_info("New link <%s> becomes standby\n", l_ptr->name); |
| 163 | return; | 163 | return; |
| 164 | } | 164 | } |
| 165 | tipc_link_send_duplicate(active[0], l_ptr); | 165 | tipc_link_dup_send_queue(active[0], l_ptr); |
| 166 | if (l_ptr->priority == active[0]->priority) { | 166 | if (l_ptr->priority == active[0]->priority) { |
| 167 | active[0] = l_ptr; | 167 | active[0] = l_ptr; |
| 168 | return; | 168 | return; |
| @@ -225,7 +225,7 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 225 | if (active[0] == l_ptr) | 225 | if (active[0] == l_ptr) |
| 226 | node_select_active_links(n_ptr); | 226 | node_select_active_links(n_ptr); |
| 227 | if (tipc_node_is_up(n_ptr)) | 227 | if (tipc_node_is_up(n_ptr)) |
| 228 | tipc_link_changeover(l_ptr); | 228 | tipc_link_failover_send_queue(l_ptr); |
| 229 | else | 229 | else |
| 230 | node_lost_contact(n_ptr); | 230 | node_lost_contact(n_ptr); |
| 231 | } | 231 | } |
| @@ -235,11 +235,6 @@ int tipc_node_active_links(struct tipc_node *n_ptr) | |||
| 235 | return n_ptr->active_links[0] != NULL; | 235 | return n_ptr->active_links[0] != NULL; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | int tipc_node_redundant_links(struct tipc_node *n_ptr) | ||
| 239 | { | ||
| 240 | return n_ptr->working_links > 1; | ||
| 241 | } | ||
| 242 | |||
| 243 | int tipc_node_is_up(struct tipc_node *n_ptr) | 238 | int tipc_node_is_up(struct tipc_node *n_ptr) |
| 244 | { | 239 | { |
| 245 | return tipc_node_active_links(n_ptr); | 240 | return tipc_node_active_links(n_ptr); |
| @@ -291,11 +286,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) | |||
| 291 | 286 | ||
| 292 | /* Flush broadcast link info associated with lost node */ | 287 | /* Flush broadcast link info associated with lost node */ |
| 293 | if (n_ptr->bclink.recv_permitted) { | 288 | if (n_ptr->bclink.recv_permitted) { |
| 294 | while (n_ptr->bclink.deferred_head) { | 289 | kfree_skb_list(n_ptr->bclink.deferred_head); |
| 295 | struct sk_buff *buf = n_ptr->bclink.deferred_head; | ||
| 296 | n_ptr->bclink.deferred_head = buf->next; | ||
| 297 | kfree_skb(buf); | ||
| 298 | } | ||
| 299 | n_ptr->bclink.deferred_size = 0; | 290 | n_ptr->bclink.deferred_size = 0; |
| 300 | 291 | ||
| 301 | if (n_ptr->bclink.reasm_head) { | 292 | if (n_ptr->bclink.reasm_head) { |
diff --git a/net/tipc/node.h b/net/tipc/node.h index e5e96c04e167..63e2e8ead2fe 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
| @@ -64,7 +64,6 @@ | |||
| 64 | * @working_links: number of working links to node (both active and standby) | 64 | * @working_links: number of working links to node (both active and standby) |
| 65 | * @block_setup: bit mask of conditions preventing link establishment to node | 65 | * @block_setup: bit mask of conditions preventing link establishment to node |
| 66 | * @link_cnt: number of links to node | 66 | * @link_cnt: number of links to node |
| 67 | * @permit_changeover: non-zero if node has redundant links to this system | ||
| 68 | * @signature: node instance identifier | 67 | * @signature: node instance identifier |
| 69 | * @bclink: broadcast-related info | 68 | * @bclink: broadcast-related info |
| 70 | * @acked: sequence # of last outbound b'cast message acknowledged by node | 69 | * @acked: sequence # of last outbound b'cast message acknowledged by node |
| @@ -89,7 +88,6 @@ struct tipc_node { | |||
| 89 | int link_cnt; | 88 | int link_cnt; |
| 90 | int working_links; | 89 | int working_links; |
| 91 | int block_setup; | 90 | int block_setup; |
| 92 | int permit_changeover; | ||
| 93 | u32 signature; | 91 | u32 signature; |
| 94 | struct { | 92 | struct { |
| 95 | u32 acked; | 93 | u32 acked; |
| @@ -115,7 +113,6 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | |||
| 115 | void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | 113 | void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr); |
| 116 | void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | 114 | void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); |
| 117 | int tipc_node_active_links(struct tipc_node *n_ptr); | 115 | int tipc_node_active_links(struct tipc_node *n_ptr); |
| 118 | int tipc_node_redundant_links(struct tipc_node *n_ptr); | ||
| 119 | int tipc_node_is_up(struct tipc_node *n_ptr); | 116 | int tipc_node_is_up(struct tipc_node *n_ptr); |
| 120 | struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); | 117 | struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); |
| 121 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); | 118 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); |
diff --git a/net/tipc/port.c b/net/tipc/port.c index d43f3182b1d4..b742b2654525 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
| @@ -817,17 +817,14 @@ exit: | |||
| 817 | */ | 817 | */ |
| 818 | int __tipc_disconnect(struct tipc_port *tp_ptr) | 818 | int __tipc_disconnect(struct tipc_port *tp_ptr) |
| 819 | { | 819 | { |
| 820 | int res; | ||
| 821 | |||
| 822 | if (tp_ptr->connected) { | 820 | if (tp_ptr->connected) { |
| 823 | tp_ptr->connected = 0; | 821 | tp_ptr->connected = 0; |
| 824 | /* let timer expire on it's own to avoid deadlock! */ | 822 | /* let timer expire on it's own to avoid deadlock! */ |
| 825 | tipc_nodesub_unsubscribe(&tp_ptr->subscription); | 823 | tipc_nodesub_unsubscribe(&tp_ptr->subscription); |
| 826 | res = 0; | 824 | return 0; |
| 827 | } else { | ||
| 828 | res = -ENOTCONN; | ||
| 829 | } | 825 | } |
| 830 | return res; | 826 | |
| 827 | return -ENOTCONN; | ||
| 831 | } | 828 | } |
| 832 | 829 | ||
| 833 | /* | 830 | /* |
diff --git a/net/tipc/ref.c b/net/tipc/ref.c index 2a2a938dc22c..de3d593e2fee 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c | |||
| @@ -126,9 +126,6 @@ int tipc_ref_table_init(u32 requested_size, u32 start) | |||
| 126 | */ | 126 | */ |
| 127 | void tipc_ref_table_stop(void) | 127 | void tipc_ref_table_stop(void) |
| 128 | { | 128 | { |
| 129 | if (!tipc_ref_table.entries) | ||
| 130 | return; | ||
| 131 | |||
| 132 | vfree(tipc_ref_table.entries); | 129 | vfree(tipc_ref_table.entries); |
| 133 | tipc_ref_table.entries = NULL; | 130 | tipc_ref_table.entries = NULL; |
| 134 | } | 131 | } |
diff --git a/net/tipc/server.c b/net/tipc/server.c index fd3fa57a410e..646a930eefbf 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c | |||
| @@ -55,7 +55,7 @@ | |||
| 55 | * @usr_data: user-specified field | 55 | * @usr_data: user-specified field |
| 56 | * @rx_action: what to do when connection socket is active | 56 | * @rx_action: what to do when connection socket is active |
| 57 | * @outqueue: pointer to first outbound message in queue | 57 | * @outqueue: pointer to first outbound message in queue |
| 58 | * @outqueue_lock: controll access to the outqueue | 58 | * @outqueue_lock: control access to the outqueue |
| 59 | * @outqueue: list of connection objects for its server | 59 | * @outqueue: list of connection objects for its server |
| 60 | * @swork: send work item | 60 | * @swork: send work item |
| 61 | */ | 61 | */ |
| @@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con); | |||
| 87 | static void tipc_conn_kref_release(struct kref *kref) | 87 | static void tipc_conn_kref_release(struct kref *kref) |
| 88 | { | 88 | { |
| 89 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); | 89 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); |
| 90 | struct tipc_server *s = con->server; | ||
| 91 | 90 | ||
| 92 | if (con->sock) { | 91 | if (con->sock) { |
| 93 | tipc_sock_release_local(con->sock); | 92 | tipc_sock_release_local(con->sock); |
| @@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref) | |||
| 95 | } | 94 | } |
| 96 | 95 | ||
| 97 | tipc_clean_outqueues(con); | 96 | tipc_clean_outqueues(con); |
| 98 | |||
| 99 | if (con->conid) | ||
| 100 | s->tipc_conn_shutdown(con->conid, con->usr_data); | ||
| 101 | |||
| 102 | kfree(con); | 97 | kfree(con); |
| 103 | } | 98 | } |
| 104 | 99 | ||
| @@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con) | |||
| 181 | struct tipc_server *s = con->server; | 176 | struct tipc_server *s = con->server; |
| 182 | 177 | ||
| 183 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { | 178 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { |
| 179 | if (con->conid) | ||
| 180 | s->tipc_conn_shutdown(con->conid, con->usr_data); | ||
| 181 | |||
| 184 | spin_lock_bh(&s->idr_lock); | 182 | spin_lock_bh(&s->idr_lock); |
| 185 | idr_remove(&s->conn_idr, con->conid); | 183 | idr_remove(&s->conn_idr, con->conid); |
| 186 | s->idr_in_use--; | 184 | s->idr_in_use--; |
| @@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid, | |||
| 429 | list_add_tail(&e->list, &con->outqueue); | 427 | list_add_tail(&e->list, &con->outqueue); |
| 430 | spin_unlock_bh(&con->outqueue_lock); | 428 | spin_unlock_bh(&con->outqueue_lock); |
| 431 | 429 | ||
| 432 | if (test_bit(CF_CONNECTED, &con->flags)) | 430 | if (test_bit(CF_CONNECTED, &con->flags)) { |
| 433 | if (!queue_work(s->send_wq, &con->swork)) | 431 | if (!queue_work(s->send_wq, &con->swork)) |
| 434 | conn_put(con); | 432 | conn_put(con); |
| 435 | 433 | } else { | |
| 434 | conn_put(con); | ||
| 435 | } | ||
| 436 | return 0; | 436 | return 0; |
| 437 | } | 437 | } |
| 438 | 438 | ||
| @@ -573,7 +573,6 @@ int tipc_server_start(struct tipc_server *s) | |||
| 573 | kmem_cache_destroy(s->rcvbuf_cache); | 573 | kmem_cache_destroy(s->rcvbuf_cache); |
| 574 | return ret; | 574 | return ret; |
| 575 | } | 575 | } |
| 576 | s->enabled = 1; | ||
| 577 | return ret; | 576 | return ret; |
| 578 | } | 577 | } |
| 579 | 578 | ||
| @@ -583,10 +582,6 @@ void tipc_server_stop(struct tipc_server *s) | |||
| 583 | int total = 0; | 582 | int total = 0; |
| 584 | int id; | 583 | int id; |
| 585 | 584 | ||
| 586 | if (!s->enabled) | ||
| 587 | return; | ||
| 588 | |||
| 589 | s->enabled = 0; | ||
| 590 | spin_lock_bh(&s->idr_lock); | 585 | spin_lock_bh(&s->idr_lock); |
| 591 | for (id = 0; total < s->idr_in_use; id++) { | 586 | for (id = 0; total < s->idr_in_use; id++) { |
| 592 | con = idr_find(&s->conn_idr, id); | 587 | con = idr_find(&s->conn_idr, id); |
diff --git a/net/tipc/server.h b/net/tipc/server.h index 98b23f20bc0f..be817b0b547e 100644 --- a/net/tipc/server.h +++ b/net/tipc/server.h | |||
| @@ -56,7 +56,6 @@ | |||
| 56 | * @name: server name | 56 | * @name: server name |
| 57 | * @imp: message importance | 57 | * @imp: message importance |
| 58 | * @type: socket type | 58 | * @type: socket type |
| 59 | * @enabled: identify whether server is launched or not | ||
| 60 | */ | 59 | */ |
| 61 | struct tipc_server { | 60 | struct tipc_server { |
| 62 | struct idr conn_idr; | 61 | struct idr conn_idr; |
| @@ -74,7 +73,6 @@ struct tipc_server { | |||
| 74 | const char name[TIPC_SERVER_NAME_LEN]; | 73 | const char name[TIPC_SERVER_NAME_LEN]; |
| 75 | int imp; | 74 | int imp; |
| 76 | int type; | 75 | int type; |
| 77 | int enabled; | ||
| 78 | }; | 76 | }; |
| 79 | 77 | ||
| 80 | int tipc_conn_sendmsg(struct tipc_server *s, int conid, | 78 | int tipc_conn_sendmsg(struct tipc_server *s, int conid, |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e741416d1d24..0ed0eaa62f29 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -55,9 +55,6 @@ struct tipc_sock { | |||
| 55 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) | 55 | #define tipc_sk(sk) ((struct tipc_sock *)(sk)) |
| 56 | #define tipc_sk_port(sk) (tipc_sk(sk)->p) | 56 | #define tipc_sk_port(sk) (tipc_sk(sk)->p) |
| 57 | 57 | ||
| 58 | #define tipc_rx_ready(sock) (!skb_queue_empty(&sock->sk->sk_receive_queue) || \ | ||
| 59 | (sock->state == SS_DISCONNECTING)) | ||
| 60 | |||
| 61 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); | 58 | static int backlog_rcv(struct sock *sk, struct sk_buff *skb); |
| 62 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); | 59 | static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); |
| 63 | static void wakeupdispatch(struct tipc_port *tport); | 60 | static void wakeupdispatch(struct tipc_port *tport); |
| @@ -73,8 +70,6 @@ static const struct proto_ops msg_ops; | |||
| 73 | static struct proto tipc_proto; | 70 | static struct proto tipc_proto; |
| 74 | static struct proto tipc_proto_kern; | 71 | static struct proto tipc_proto_kern; |
| 75 | 72 | ||
| 76 | static int sockets_enabled; | ||
| 77 | |||
| 78 | /* | 73 | /* |
| 79 | * Revised TIPC socket locking policy: | 74 | * Revised TIPC socket locking policy: |
| 80 | * | 75 | * |
| @@ -239,7 +234,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol, | |||
| 239 | int tipc_sock_create_local(int type, struct socket **res) | 234 | int tipc_sock_create_local(int type, struct socket **res) |
| 240 | { | 235 | { |
| 241 | int rc; | 236 | int rc; |
| 242 | struct sock *sk; | ||
| 243 | 237 | ||
| 244 | rc = sock_create_lite(AF_TIPC, type, 0, res); | 238 | rc = sock_create_lite(AF_TIPC, type, 0, res); |
| 245 | if (rc < 0) { | 239 | if (rc < 0) { |
| @@ -248,8 +242,6 @@ int tipc_sock_create_local(int type, struct socket **res) | |||
| 248 | } | 242 | } |
| 249 | tipc_sk_create(&init_net, *res, 0, 1); | 243 | tipc_sk_create(&init_net, *res, 0, 1); |
| 250 | 244 | ||
| 251 | sk = (*res)->sk; | ||
| 252 | |||
| 253 | return 0; | 245 | return 0; |
| 254 | } | 246 | } |
| 255 | 247 | ||
| @@ -570,6 +562,31 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | |||
| 570 | return 0; | 562 | return 0; |
| 571 | } | 563 | } |
| 572 | 564 | ||
| 565 | static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | ||
| 566 | { | ||
| 567 | struct sock *sk = sock->sk; | ||
| 568 | struct tipc_port *tport = tipc_sk_port(sk); | ||
| 569 | DEFINE_WAIT(wait); | ||
| 570 | int done; | ||
| 571 | |||
| 572 | do { | ||
| 573 | int err = sock_error(sk); | ||
| 574 | if (err) | ||
| 575 | return err; | ||
| 576 | if (sock->state == SS_DISCONNECTING) | ||
| 577 | return -EPIPE; | ||
| 578 | if (!*timeo_p) | ||
| 579 | return -EAGAIN; | ||
| 580 | if (signal_pending(current)) | ||
| 581 | return sock_intr_errno(*timeo_p); | ||
| 582 | |||
| 583 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 584 | done = sk_wait_event(sk, timeo_p, !tport->congested); | ||
| 585 | finish_wait(sk_sleep(sk), &wait); | ||
| 586 | } while (!done); | ||
| 587 | return 0; | ||
| 588 | } | ||
| 589 | |||
| 573 | /** | 590 | /** |
| 574 | * send_msg - send message in connectionless manner | 591 | * send_msg - send message in connectionless manner |
| 575 | * @iocb: if NULL, indicates that socket lock is already held | 592 | * @iocb: if NULL, indicates that socket lock is already held |
| @@ -589,9 +606,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 589 | { | 606 | { |
| 590 | struct sock *sk = sock->sk; | 607 | struct sock *sk = sock->sk; |
| 591 | struct tipc_port *tport = tipc_sk_port(sk); | 608 | struct tipc_port *tport = tipc_sk_port(sk); |
| 592 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 609 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 593 | int needs_conn; | 610 | int needs_conn; |
| 594 | long timeout_val; | 611 | long timeo; |
| 595 | int res = -EINVAL; | 612 | int res = -EINVAL; |
| 596 | 613 | ||
| 597 | if (unlikely(!dest)) | 614 | if (unlikely(!dest)) |
| @@ -628,8 +645,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 628 | reject_rx_queue(sk); | 645 | reject_rx_queue(sk); |
| 629 | } | 646 | } |
| 630 | 647 | ||
| 631 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 648 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
| 632 | |||
| 633 | do { | 649 | do { |
| 634 | if (dest->addrtype == TIPC_ADDR_NAME) { | 650 | if (dest->addrtype == TIPC_ADDR_NAME) { |
| 635 | res = dest_name_check(dest, m); | 651 | res = dest_name_check(dest, m); |
| @@ -663,14 +679,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
| 663 | sock->state = SS_CONNECTING; | 679 | sock->state = SS_CONNECTING; |
| 664 | break; | 680 | break; |
| 665 | } | 681 | } |
| 666 | if (timeout_val <= 0L) { | 682 | res = tipc_wait_for_sndmsg(sock, &timeo); |
| 667 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 683 | if (res) |
| 668 | break; | 684 | break; |
| 669 | } | ||
| 670 | release_sock(sk); | ||
| 671 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 672 | !tport->congested, timeout_val); | ||
| 673 | lock_sock(sk); | ||
| 674 | } while (1); | 685 | } while (1); |
| 675 | 686 | ||
| 676 | exit: | 687 | exit: |
| @@ -679,6 +690,34 @@ exit: | |||
| 679 | return res; | 690 | return res; |
| 680 | } | 691 | } |
| 681 | 692 | ||
| 693 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | ||
| 694 | { | ||
| 695 | struct sock *sk = sock->sk; | ||
| 696 | struct tipc_port *tport = tipc_sk_port(sk); | ||
| 697 | DEFINE_WAIT(wait); | ||
| 698 | int done; | ||
| 699 | |||
| 700 | do { | ||
| 701 | int err = sock_error(sk); | ||
| 702 | if (err) | ||
| 703 | return err; | ||
| 704 | if (sock->state == SS_DISCONNECTING) | ||
| 705 | return -EPIPE; | ||
| 706 | else if (sock->state != SS_CONNECTED) | ||
| 707 | return -ENOTCONN; | ||
| 708 | if (!*timeo_p) | ||
| 709 | return -EAGAIN; | ||
| 710 | if (signal_pending(current)) | ||
| 711 | return sock_intr_errno(*timeo_p); | ||
| 712 | |||
| 713 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 714 | done = sk_wait_event(sk, timeo_p, | ||
| 715 | (!tport->congested || !tport->connected)); | ||
| 716 | finish_wait(sk_sleep(sk), &wait); | ||
| 717 | } while (!done); | ||
| 718 | return 0; | ||
| 719 | } | ||
| 720 | |||
| 682 | /** | 721 | /** |
| 683 | * send_packet - send a connection-oriented message | 722 | * send_packet - send a connection-oriented message |
| 684 | * @iocb: if NULL, indicates that socket lock is already held | 723 | * @iocb: if NULL, indicates that socket lock is already held |
| @@ -695,9 +734,9 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 695 | { | 734 | { |
| 696 | struct sock *sk = sock->sk; | 735 | struct sock *sk = sock->sk; |
| 697 | struct tipc_port *tport = tipc_sk_port(sk); | 736 | struct tipc_port *tport = tipc_sk_port(sk); |
| 698 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 737 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 699 | long timeout_val; | 738 | int res = -EINVAL; |
| 700 | int res; | 739 | long timeo; |
| 701 | 740 | ||
| 702 | /* Handle implied connection establishment */ | 741 | /* Handle implied connection establishment */ |
| 703 | if (unlikely(dest)) | 742 | if (unlikely(dest)) |
| @@ -709,30 +748,24 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 709 | if (iocb) | 748 | if (iocb) |
| 710 | lock_sock(sk); | 749 | lock_sock(sk); |
| 711 | 750 | ||
| 712 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 751 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 752 | if (sock->state == SS_DISCONNECTING) | ||
| 753 | res = -EPIPE; | ||
| 754 | else | ||
| 755 | res = -ENOTCONN; | ||
| 756 | goto exit; | ||
| 757 | } | ||
| 713 | 758 | ||
| 759 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | ||
| 714 | do { | 760 | do { |
| 715 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
| 716 | if (sock->state == SS_DISCONNECTING) | ||
| 717 | res = -EPIPE; | ||
| 718 | else | ||
| 719 | res = -ENOTCONN; | ||
| 720 | break; | ||
| 721 | } | ||
| 722 | |||
| 723 | res = tipc_send(tport->ref, m->msg_iov, total_len); | 761 | res = tipc_send(tport->ref, m->msg_iov, total_len); |
| 724 | if (likely(res != -ELINKCONG)) | 762 | if (likely(res != -ELINKCONG)) |
| 725 | break; | 763 | break; |
| 726 | if (timeout_val <= 0L) { | 764 | res = tipc_wait_for_sndpkt(sock, &timeo); |
| 727 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 765 | if (res) |
| 728 | break; | 766 | break; |
| 729 | } | ||
| 730 | release_sock(sk); | ||
| 731 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 732 | (!tport->congested || !tport->connected), timeout_val); | ||
| 733 | lock_sock(sk); | ||
| 734 | } while (1); | 767 | } while (1); |
| 735 | 768 | exit: | |
| 736 | if (iocb) | 769 | if (iocb) |
| 737 | release_sock(sk); | 770 | release_sock(sk); |
| 738 | return res; | 771 | return res; |
| @@ -770,16 +803,11 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, | |||
| 770 | 803 | ||
| 771 | /* Handle special cases where there is no connection */ | 804 | /* Handle special cases where there is no connection */ |
| 772 | if (unlikely(sock->state != SS_CONNECTED)) { | 805 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 773 | if (sock->state == SS_UNCONNECTED) { | 806 | if (sock->state == SS_UNCONNECTED) |
| 774 | res = send_packet(NULL, sock, m, total_len); | 807 | res = send_packet(NULL, sock, m, total_len); |
| 775 | goto exit; | 808 | else |
| 776 | } else if (sock->state == SS_DISCONNECTING) { | 809 | res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; |
| 777 | res = -EPIPE; | 810 | goto exit; |
| 778 | goto exit; | ||
| 779 | } else { | ||
| 780 | res = -ENOTCONN; | ||
| 781 | goto exit; | ||
| 782 | } | ||
| 783 | } | 811 | } |
| 784 | 812 | ||
| 785 | if (unlikely(m->msg_name)) { | 813 | if (unlikely(m->msg_name)) { |
| @@ -876,7 +904,7 @@ static int auto_connect(struct socket *sock, struct tipc_msg *msg) | |||
| 876 | */ | 904 | */ |
| 877 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | 905 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) |
| 878 | { | 906 | { |
| 879 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; | 907 | DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name); |
| 880 | 908 | ||
| 881 | if (addr) { | 909 | if (addr) { |
| 882 | addr->family = AF_TIPC; | 910 | addr->family = AF_TIPC; |
| @@ -961,6 +989,37 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | |||
| 961 | return 0; | 989 | return 0; |
| 962 | } | 990 | } |
| 963 | 991 | ||
| 992 | static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo) | ||
| 993 | { | ||
| 994 | struct sock *sk = sock->sk; | ||
| 995 | DEFINE_WAIT(wait); | ||
| 996 | int err; | ||
| 997 | |||
| 998 | for (;;) { | ||
| 999 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 1000 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { | ||
| 1001 | if (sock->state == SS_DISCONNECTING) { | ||
| 1002 | err = -ENOTCONN; | ||
| 1003 | break; | ||
| 1004 | } | ||
| 1005 | release_sock(sk); | ||
| 1006 | timeo = schedule_timeout(timeo); | ||
| 1007 | lock_sock(sk); | ||
| 1008 | } | ||
| 1009 | err = 0; | ||
| 1010 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
| 1011 | break; | ||
| 1012 | err = sock_intr_errno(timeo); | ||
| 1013 | if (signal_pending(current)) | ||
| 1014 | break; | ||
| 1015 | err = -EAGAIN; | ||
| 1016 | if (!timeo) | ||
| 1017 | break; | ||
| 1018 | } | ||
| 1019 | finish_wait(sk_sleep(sk), &wait); | ||
| 1020 | return err; | ||
| 1021 | } | ||
| 1022 | |||
| 964 | /** | 1023 | /** |
| 965 | * recv_msg - receive packet-oriented message | 1024 | * recv_msg - receive packet-oriented message |
| 966 | * @iocb: (unused) | 1025 | * @iocb: (unused) |
| @@ -980,7 +1039,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
| 980 | struct tipc_port *tport = tipc_sk_port(sk); | 1039 | struct tipc_port *tport = tipc_sk_port(sk); |
| 981 | struct sk_buff *buf; | 1040 | struct sk_buff *buf; |
| 982 | struct tipc_msg *msg; | 1041 | struct tipc_msg *msg; |
| 983 | long timeout; | 1042 | long timeo; |
| 984 | unsigned int sz; | 1043 | unsigned int sz; |
| 985 | u32 err; | 1044 | u32 err; |
| 986 | int res; | 1045 | int res; |
| @@ -996,25 +1055,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
| 996 | goto exit; | 1055 | goto exit; |
| 997 | } | 1056 | } |
| 998 | 1057 | ||
| 999 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | 1058 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
| 1000 | restart: | 1059 | restart: |
| 1001 | 1060 | ||
| 1002 | /* Look for a message in receive queue; wait if necessary */ | 1061 | /* Look for a message in receive queue; wait if necessary */ |
| 1003 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1062 | res = tipc_wait_for_rcvmsg(sock, timeo); |
| 1004 | if (sock->state == SS_DISCONNECTING) { | 1063 | if (res) |
| 1005 | res = -ENOTCONN; | 1064 | goto exit; |
| 1006 | goto exit; | ||
| 1007 | } | ||
| 1008 | if (timeout <= 0L) { | ||
| 1009 | res = timeout ? timeout : -EWOULDBLOCK; | ||
| 1010 | goto exit; | ||
| 1011 | } | ||
| 1012 | release_sock(sk); | ||
| 1013 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1014 | tipc_rx_ready(sock), | ||
| 1015 | timeout); | ||
| 1016 | lock_sock(sk); | ||
| 1017 | } | ||
| 1018 | 1065 | ||
| 1019 | /* Look at first message in receive queue */ | 1066 | /* Look at first message in receive queue */ |
| 1020 | buf = skb_peek(&sk->sk_receive_queue); | 1067 | buf = skb_peek(&sk->sk_receive_queue); |
| @@ -1086,7 +1133,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
| 1086 | struct tipc_port *tport = tipc_sk_port(sk); | 1133 | struct tipc_port *tport = tipc_sk_port(sk); |
| 1087 | struct sk_buff *buf; | 1134 | struct sk_buff *buf; |
| 1088 | struct tipc_msg *msg; | 1135 | struct tipc_msg *msg; |
| 1089 | long timeout; | 1136 | long timeo; |
| 1090 | unsigned int sz; | 1137 | unsigned int sz; |
| 1091 | int sz_to_copy, target, needed; | 1138 | int sz_to_copy, target, needed; |
| 1092 | int sz_copied = 0; | 1139 | int sz_copied = 0; |
| @@ -1099,31 +1146,19 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
| 1099 | 1146 | ||
| 1100 | lock_sock(sk); | 1147 | lock_sock(sk); |
| 1101 | 1148 | ||
| 1102 | if (unlikely((sock->state == SS_UNCONNECTED))) { | 1149 | if (unlikely(sock->state == SS_UNCONNECTED)) { |
| 1103 | res = -ENOTCONN; | 1150 | res = -ENOTCONN; |
| 1104 | goto exit; | 1151 | goto exit; |
| 1105 | } | 1152 | } |
| 1106 | 1153 | ||
| 1107 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); | 1154 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); |
| 1108 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | 1155 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
| 1109 | 1156 | ||
| 1110 | restart: | 1157 | restart: |
| 1111 | /* Look for a message in receive queue; wait if necessary */ | 1158 | /* Look for a message in receive queue; wait if necessary */ |
| 1112 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1159 | res = tipc_wait_for_rcvmsg(sock, timeo); |
| 1113 | if (sock->state == SS_DISCONNECTING) { | 1160 | if (res) |
| 1114 | res = -ENOTCONN; | 1161 | goto exit; |
| 1115 | goto exit; | ||
| 1116 | } | ||
| 1117 | if (timeout <= 0L) { | ||
| 1118 | res = timeout ? timeout : -EWOULDBLOCK; | ||
| 1119 | goto exit; | ||
| 1120 | } | ||
| 1121 | release_sock(sk); | ||
| 1122 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1123 | tipc_rx_ready(sock), | ||
| 1124 | timeout); | ||
| 1125 | lock_sock(sk); | ||
| 1126 | } | ||
| 1127 | 1162 | ||
| 1128 | /* Look at first message in receive queue */ | 1163 | /* Look at first message in receive queue */ |
| 1129 | buf = skb_peek(&sk->sk_receive_queue); | 1164 | buf = skb_peek(&sk->sk_receive_queue); |
| @@ -1327,14 +1362,12 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) | |||
| 1327 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) | 1362 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) |
| 1328 | { | 1363 | { |
| 1329 | struct tipc_msg *msg = buf_msg(buf); | 1364 | struct tipc_msg *msg = buf_msg(buf); |
| 1330 | unsigned int limit; | ||
| 1331 | 1365 | ||
| 1332 | if (msg_connected(msg)) | 1366 | if (msg_connected(msg)) |
| 1333 | limit = sysctl_tipc_rmem[2]; | 1367 | return sysctl_tipc_rmem[2]; |
| 1334 | else | 1368 | |
| 1335 | limit = sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << | 1369 | return sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << |
| 1336 | msg_importance(msg); | 1370 | msg_importance(msg); |
| 1337 | return limit; | ||
| 1338 | } | 1371 | } |
| 1339 | 1372 | ||
| 1340 | /** | 1373 | /** |
| @@ -1448,6 +1481,28 @@ static void wakeupdispatch(struct tipc_port *tport) | |||
| 1448 | sk->sk_write_space(sk); | 1481 | sk->sk_write_space(sk); |
| 1449 | } | 1482 | } |
| 1450 | 1483 | ||
| 1484 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) | ||
| 1485 | { | ||
| 1486 | struct sock *sk = sock->sk; | ||
| 1487 | DEFINE_WAIT(wait); | ||
| 1488 | int done; | ||
| 1489 | |||
| 1490 | do { | ||
| 1491 | int err = sock_error(sk); | ||
| 1492 | if (err) | ||
| 1493 | return err; | ||
| 1494 | if (!*timeo_p) | ||
| 1495 | return -ETIMEDOUT; | ||
| 1496 | if (signal_pending(current)) | ||
| 1497 | return sock_intr_errno(*timeo_p); | ||
| 1498 | |||
| 1499 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 1500 | done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); | ||
| 1501 | finish_wait(sk_sleep(sk), &wait); | ||
| 1502 | } while (!done); | ||
| 1503 | return 0; | ||
| 1504 | } | ||
| 1505 | |||
| 1451 | /** | 1506 | /** |
| 1452 | * connect - establish a connection to another TIPC port | 1507 | * connect - establish a connection to another TIPC port |
| 1453 | * @sock: socket structure | 1508 | * @sock: socket structure |
| @@ -1463,7 +1518,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1463 | struct sock *sk = sock->sk; | 1518 | struct sock *sk = sock->sk; |
| 1464 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; | 1519 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; |
| 1465 | struct msghdr m = {NULL,}; | 1520 | struct msghdr m = {NULL,}; |
| 1466 | unsigned int timeout; | 1521 | long timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; |
| 1522 | socket_state previous; | ||
| 1467 | int res; | 1523 | int res; |
| 1468 | 1524 | ||
| 1469 | lock_sock(sk); | 1525 | lock_sock(sk); |
| @@ -1485,8 +1541,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1485 | goto exit; | 1541 | goto exit; |
| 1486 | } | 1542 | } |
| 1487 | 1543 | ||
| 1488 | timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; | 1544 | previous = sock->state; |
| 1489 | |||
| 1490 | switch (sock->state) { | 1545 | switch (sock->state) { |
| 1491 | case SS_UNCONNECTED: | 1546 | case SS_UNCONNECTED: |
| 1492 | /* Send a 'SYN-' to destination */ | 1547 | /* Send a 'SYN-' to destination */ |
| @@ -1508,43 +1563,22 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
| 1508 | * case is EINPROGRESS, rather than EALREADY. | 1563 | * case is EINPROGRESS, rather than EALREADY. |
| 1509 | */ | 1564 | */ |
| 1510 | res = -EINPROGRESS; | 1565 | res = -EINPROGRESS; |
| 1511 | break; | ||
| 1512 | case SS_CONNECTING: | 1566 | case SS_CONNECTING: |
| 1513 | res = -EALREADY; | 1567 | if (previous == SS_CONNECTING) |
| 1568 | res = -EALREADY; | ||
| 1569 | if (!timeout) | ||
| 1570 | goto exit; | ||
| 1571 | timeout = msecs_to_jiffies(timeout); | ||
| 1572 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
| 1573 | res = tipc_wait_for_connect(sock, &timeout); | ||
| 1514 | break; | 1574 | break; |
| 1515 | case SS_CONNECTED: | 1575 | case SS_CONNECTED: |
| 1516 | res = -EISCONN; | 1576 | res = -EISCONN; |
| 1517 | break; | 1577 | break; |
| 1518 | default: | 1578 | default: |
| 1519 | res = -EINVAL; | 1579 | res = -EINVAL; |
| 1520 | goto exit; | 1580 | break; |
| 1521 | } | ||
| 1522 | |||
| 1523 | if (sock->state == SS_CONNECTING) { | ||
| 1524 | if (!timeout) | ||
| 1525 | goto exit; | ||
| 1526 | |||
| 1527 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
| 1528 | release_sock(sk); | ||
| 1529 | res = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
| 1530 | sock->state != SS_CONNECTING, | ||
| 1531 | timeout ? (long)msecs_to_jiffies(timeout) | ||
| 1532 | : MAX_SCHEDULE_TIMEOUT); | ||
| 1533 | lock_sock(sk); | ||
| 1534 | if (res <= 0) { | ||
| 1535 | if (res == 0) | ||
| 1536 | res = -ETIMEDOUT; | ||
| 1537 | else | ||
| 1538 | ; /* leave "res" unchanged */ | ||
| 1539 | goto exit; | ||
| 1540 | } | ||
| 1541 | } | 1581 | } |
| 1542 | |||
| 1543 | if (unlikely(sock->state == SS_DISCONNECTING)) | ||
| 1544 | res = sock_error(sk); | ||
| 1545 | else | ||
| 1546 | res = 0; | ||
| 1547 | |||
| 1548 | exit: | 1582 | exit: |
| 1549 | release_sock(sk); | 1583 | release_sock(sk); |
| 1550 | return res; | 1584 | return res; |
| @@ -1575,6 +1609,42 @@ static int listen(struct socket *sock, int len) | |||
| 1575 | return res; | 1609 | return res; |
| 1576 | } | 1610 | } |
| 1577 | 1611 | ||
| 1612 | static int tipc_wait_for_accept(struct socket *sock, long timeo) | ||
| 1613 | { | ||
| 1614 | struct sock *sk = sock->sk; | ||
| 1615 | DEFINE_WAIT(wait); | ||
| 1616 | int err; | ||
| 1617 | |||
| 1618 | /* True wake-one mechanism for incoming connections: only | ||
| 1619 | * one process gets woken up, not the 'whole herd'. | ||
| 1620 | * Since we do not 'race & poll' for established sockets | ||
| 1621 | * anymore, the common case will execute the loop only once. | ||
| 1622 | */ | ||
| 1623 | for (;;) { | ||
| 1624 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, | ||
| 1625 | TASK_INTERRUPTIBLE); | ||
| 1626 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { | ||
| 1627 | release_sock(sk); | ||
| 1628 | timeo = schedule_timeout(timeo); | ||
| 1629 | lock_sock(sk); | ||
| 1630 | } | ||
| 1631 | err = 0; | ||
| 1632 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
| 1633 | break; | ||
| 1634 | err = -EINVAL; | ||
| 1635 | if (sock->state != SS_LISTENING) | ||
| 1636 | break; | ||
| 1637 | err = sock_intr_errno(timeo); | ||
| 1638 | if (signal_pending(current)) | ||
| 1639 | break; | ||
| 1640 | err = -EAGAIN; | ||
| 1641 | if (!timeo) | ||
| 1642 | break; | ||
| 1643 | } | ||
| 1644 | finish_wait(sk_sleep(sk), &wait); | ||
| 1645 | return err; | ||
| 1646 | } | ||
| 1647 | |||
| 1578 | /** | 1648 | /** |
| 1579 | * accept - wait for connection request | 1649 | * accept - wait for connection request |
| 1580 | * @sock: listening socket | 1650 | * @sock: listening socket |
| @@ -1591,7 +1661,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
| 1591 | struct tipc_port *new_tport; | 1661 | struct tipc_port *new_tport; |
| 1592 | struct tipc_msg *msg; | 1662 | struct tipc_msg *msg; |
| 1593 | u32 new_ref; | 1663 | u32 new_ref; |
| 1594 | 1664 | long timeo; | |
| 1595 | int res; | 1665 | int res; |
| 1596 | 1666 | ||
| 1597 | lock_sock(sk); | 1667 | lock_sock(sk); |
| @@ -1601,18 +1671,10 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
| 1601 | goto exit; | 1671 | goto exit; |
| 1602 | } | 1672 | } |
| 1603 | 1673 | ||
| 1604 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1674 | timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); |
| 1605 | if (flags & O_NONBLOCK) { | 1675 | res = tipc_wait_for_accept(sock, timeo); |
| 1606 | res = -EWOULDBLOCK; | 1676 | if (res) |
| 1607 | goto exit; | 1677 | goto exit; |
| 1608 | } | ||
| 1609 | release_sock(sk); | ||
| 1610 | res = wait_event_interruptible(*sk_sleep(sk), | ||
| 1611 | (!skb_queue_empty(&sk->sk_receive_queue))); | ||
| 1612 | lock_sock(sk); | ||
| 1613 | if (res) | ||
| 1614 | goto exit; | ||
| 1615 | } | ||
| 1616 | 1678 | ||
| 1617 | buf = skb_peek(&sk->sk_receive_queue); | 1679 | buf = skb_peek(&sk->sk_receive_queue); |
| 1618 | 1680 | ||
| @@ -1963,8 +2025,6 @@ int tipc_socket_init(void) | |||
| 1963 | proto_unregister(&tipc_proto); | 2025 | proto_unregister(&tipc_proto); |
| 1964 | goto out; | 2026 | goto out; |
| 1965 | } | 2027 | } |
| 1966 | |||
| 1967 | sockets_enabled = 1; | ||
| 1968 | out: | 2028 | out: |
| 1969 | return res; | 2029 | return res; |
| 1970 | } | 2030 | } |
| @@ -1974,10 +2034,6 @@ int tipc_socket_init(void) | |||
| 1974 | */ | 2034 | */ |
| 1975 | void tipc_socket_stop(void) | 2035 | void tipc_socket_stop(void) |
| 1976 | { | 2036 | { |
| 1977 | if (!sockets_enabled) | ||
| 1978 | return; | ||
| 1979 | |||
| 1980 | sockets_enabled = 0; | ||
| 1981 | sock_unregister(tipc_family_ops.family); | 2037 | sock_unregister(tipc_family_ops.family); |
| 1982 | proto_unregister(&tipc_proto); | 2038 | proto_unregister(&tipc_proto); |
| 1983 | } | 2039 | } |
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index d38bb45d82e9..642437231ad5 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c | |||
| @@ -42,7 +42,7 @@ | |||
| 42 | /** | 42 | /** |
| 43 | * struct tipc_subscriber - TIPC network topology subscriber | 43 | * struct tipc_subscriber - TIPC network topology subscriber |
| 44 | * @conid: connection identifier to server connecting to subscriber | 44 | * @conid: connection identifier to server connecting to subscriber |
| 45 | * @lock: controll access to subscriber | 45 | * @lock: control access to subscriber |
| 46 | * @subscription_list: list of subscription objects for this subscriber | 46 | * @subscription_list: list of subscription objects for this subscriber |
| 47 | */ | 47 | */ |
| 48 | struct tipc_subscriber { | 48 | struct tipc_subscriber { |
| @@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower, | |||
| 96 | { | 96 | { |
| 97 | struct tipc_subscriber *subscriber = sub->subscriber; | 97 | struct tipc_subscriber *subscriber = sub->subscriber; |
| 98 | struct kvec msg_sect; | 98 | struct kvec msg_sect; |
| 99 | int ret; | ||
| 100 | 99 | ||
| 101 | msg_sect.iov_base = (void *)&sub->evt; | 100 | msg_sect.iov_base = (void *)&sub->evt; |
| 102 | msg_sect.iov_len = sizeof(struct tipc_event); | 101 | msg_sect.iov_len = sizeof(struct tipc_event); |
| 103 | |||
| 104 | sub->evt.event = htohl(event, sub->swap); | 102 | sub->evt.event = htohl(event, sub->swap); |
| 105 | sub->evt.found_lower = htohl(found_lower, sub->swap); | 103 | sub->evt.found_lower = htohl(found_lower, sub->swap); |
| 106 | sub->evt.found_upper = htohl(found_upper, sub->swap); | 104 | sub->evt.found_upper = htohl(found_upper, sub->swap); |
| 107 | sub->evt.port.ref = htohl(port_ref, sub->swap); | 105 | sub->evt.port.ref = htohl(port_ref, sub->swap); |
| 108 | sub->evt.port.node = htohl(node, sub->swap); | 106 | sub->evt.port.node = htohl(node, sub->swap); |
| 109 | ret = tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, | 107 | tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base, |
| 110 | msg_sect.iov_base, msg_sect.iov_len); | 108 | msg_sect.iov_len); |
| 111 | if (ret < 0) | ||
| 112 | pr_err("Sending subscription event failed, no memory\n"); | ||
| 113 | } | 109 | } |
| 114 | 110 | ||
| 115 | /** | 111 | /** |
| @@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub) | |||
| 153 | /* The spin lock per subscriber is used to protect its members */ | 149 | /* The spin lock per subscriber is used to protect its members */ |
| 154 | spin_lock_bh(&subscriber->lock); | 150 | spin_lock_bh(&subscriber->lock); |
| 155 | 151 | ||
| 156 | /* Validate if the connection related to the subscriber is | ||
| 157 | * closed (in case subscriber is terminating) | ||
| 158 | */ | ||
| 159 | if (subscriber->conid == 0) { | ||
| 160 | spin_unlock_bh(&subscriber->lock); | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | |||
| 164 | /* Validate timeout (in case subscription is being cancelled) */ | 152 | /* Validate timeout (in case subscription is being cancelled) */ |
| 165 | if (sub->timeout == TIPC_WAIT_FOREVER) { | 153 | if (sub->timeout == TIPC_WAIT_FOREVER) { |
| 166 | spin_unlock_bh(&subscriber->lock); | 154 | spin_unlock_bh(&subscriber->lock); |
| @@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber) | |||
| 215 | 203 | ||
| 216 | spin_lock_bh(&subscriber->lock); | 204 | spin_lock_bh(&subscriber->lock); |
| 217 | 205 | ||
| 218 | /* Invalidate subscriber reference */ | ||
| 219 | subscriber->conid = 0; | ||
| 220 | |||
| 221 | /* Destroy any existing subscriptions for subscriber */ | 206 | /* Destroy any existing subscriptions for subscriber */ |
| 222 | list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, | 207 | list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, |
| 223 | subscription_list) { | 208 | subscription_list) { |
| @@ -278,9 +263,9 @@ static void subscr_cancel(struct tipc_subscr *s, | |||
| 278 | * | 263 | * |
| 279 | * Called with subscriber lock held. | 264 | * Called with subscriber lock held. |
| 280 | */ | 265 | */ |
| 281 | static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s, | 266 | static int subscr_subscribe(struct tipc_subscr *s, |
| 282 | struct tipc_subscriber *subscriber) | 267 | struct tipc_subscriber *subscriber, |
| 283 | { | 268 | struct tipc_subscription **sub_p) { |
| 284 | struct tipc_subscription *sub; | 269 | struct tipc_subscription *sub; |
| 285 | int swap; | 270 | int swap; |
| 286 | 271 | ||
| @@ -291,23 +276,21 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s, | |||
| 291 | if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) { | 276 | if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) { |
| 292 | s->filter &= ~htohl(TIPC_SUB_CANCEL, swap); | 277 | s->filter &= ~htohl(TIPC_SUB_CANCEL, swap); |
| 293 | subscr_cancel(s, subscriber); | 278 | subscr_cancel(s, subscriber); |
| 294 | return NULL; | 279 | return 0; |
| 295 | } | 280 | } |
| 296 | 281 | ||
| 297 | /* Refuse subscription if global limit exceeded */ | 282 | /* Refuse subscription if global limit exceeded */ |
| 298 | if (atomic_read(&subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) { | 283 | if (atomic_read(&subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) { |
| 299 | pr_warn("Subscription rejected, limit reached (%u)\n", | 284 | pr_warn("Subscription rejected, limit reached (%u)\n", |
| 300 | TIPC_MAX_SUBSCRIPTIONS); | 285 | TIPC_MAX_SUBSCRIPTIONS); |
| 301 | subscr_terminate(subscriber); | 286 | return -EINVAL; |
| 302 | return NULL; | ||
| 303 | } | 287 | } |
| 304 | 288 | ||
| 305 | /* Allocate subscription object */ | 289 | /* Allocate subscription object */ |
| 306 | sub = kmalloc(sizeof(*sub), GFP_ATOMIC); | 290 | sub = kmalloc(sizeof(*sub), GFP_ATOMIC); |
| 307 | if (!sub) { | 291 | if (!sub) { |
| 308 | pr_warn("Subscription rejected, no memory\n"); | 292 | pr_warn("Subscription rejected, no memory\n"); |
| 309 | subscr_terminate(subscriber); | 293 | return -ENOMEM; |
| 310 | return NULL; | ||
| 311 | } | 294 | } |
| 312 | 295 | ||
| 313 | /* Initialize subscription object */ | 296 | /* Initialize subscription object */ |
| @@ -321,8 +304,7 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s, | |||
| 321 | (sub->seq.lower > sub->seq.upper)) { | 304 | (sub->seq.lower > sub->seq.upper)) { |
| 322 | pr_warn("Subscription rejected, illegal request\n"); | 305 | pr_warn("Subscription rejected, illegal request\n"); |
| 323 | kfree(sub); | 306 | kfree(sub); |
| 324 | subscr_terminate(subscriber); | 307 | return -EINVAL; |
| 325 | return NULL; | ||
| 326 | } | 308 | } |
| 327 | INIT_LIST_HEAD(&sub->nameseq_list); | 309 | INIT_LIST_HEAD(&sub->nameseq_list); |
| 328 | list_add(&sub->subscription_list, &subscriber->subscription_list); | 310 | list_add(&sub->subscription_list, &subscriber->subscription_list); |
| @@ -335,8 +317,8 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s, | |||
| 335 | (Handler)subscr_timeout, (unsigned long)sub); | 317 | (Handler)subscr_timeout, (unsigned long)sub); |
| 336 | k_start_timer(&sub->timer, sub->timeout); | 318 | k_start_timer(&sub->timer, sub->timeout); |
| 337 | } | 319 | } |
| 338 | 320 | *sub_p = sub; | |
| 339 | return sub; | 321 | return 0; |
| 340 | } | 322 | } |
| 341 | 323 | ||
| 342 | /* Handle one termination request for the subscriber */ | 324 | /* Handle one termination request for the subscriber */ |
| @@ -350,10 +332,14 @@ static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr, | |||
| 350 | void *usr_data, void *buf, size_t len) | 332 | void *usr_data, void *buf, size_t len) |
| 351 | { | 333 | { |
| 352 | struct tipc_subscriber *subscriber = usr_data; | 334 | struct tipc_subscriber *subscriber = usr_data; |
| 353 | struct tipc_subscription *sub; | 335 | struct tipc_subscription *sub = NULL; |
| 354 | 336 | ||
| 355 | spin_lock_bh(&subscriber->lock); | 337 | spin_lock_bh(&subscriber->lock); |
| 356 | sub = subscr_subscribe((struct tipc_subscr *)buf, subscriber); | 338 | if (subscr_subscribe((struct tipc_subscr *)buf, subscriber, &sub) < 0) { |
| 339 | spin_unlock_bh(&subscriber->lock); | ||
| 340 | subscr_terminate(subscriber); | ||
| 341 | return; | ||
| 342 | } | ||
| 357 | if (sub) | 343 | if (sub) |
| 358 | tipc_nametbl_subscribe(sub); | 344 | tipc_nametbl_subscribe(sub); |
| 359 | spin_unlock_bh(&subscriber->lock); | 345 | spin_unlock_bh(&subscriber->lock); |
