diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/bcast.c | 24 | ||||
-rw-r--r-- | net/tipc/bearer.c | 354 | ||||
-rw-r--r-- | net/tipc/bearer.h | 64 | ||||
-rw-r--r-- | net/tipc/core.c | 15 | ||||
-rw-r--r-- | net/tipc/core.h | 30 | ||||
-rw-r--r-- | net/tipc/discover.c | 28 | ||||
-rw-r--r-- | net/tipc/eth_media.c | 328 | ||||
-rw-r--r-- | net/tipc/handler.c | 11 | ||||
-rw-r--r-- | net/tipc/ib_media.c | 319 | ||||
-rw-r--r-- | net/tipc/link.c | 714 | ||||
-rw-r--r-- | net/tipc/link.h | 49 | ||||
-rw-r--r-- | net/tipc/msg.c | 27 | ||||
-rw-r--r-- | net/tipc/msg.h | 15 | ||||
-rw-r--r-- | net/tipc/name_table.c | 3 | ||||
-rw-r--r-- | net/tipc/netlink.c | 11 | ||||
-rw-r--r-- | net/tipc/node.c | 22 | ||||
-rw-r--r-- | net/tipc/node.h | 9 | ||||
-rw-r--r-- | net/tipc/port.c | 120 | ||||
-rw-r--r-- | net/tipc/port.h | 22 | ||||
-rw-r--r-- | net/tipc/server.c | 2 | ||||
-rw-r--r-- | net/tipc/socket.c | 394 | ||||
-rw-r--r-- | net/tipc/subscr.c | 2 |
22 files changed, 948 insertions, 1615 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 716de1ac6cb5..bf860d9e75af 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
@@ -480,18 +480,24 @@ receive: | |||
480 | tipc_node_unlock(node); | 480 | tipc_node_unlock(node); |
481 | tipc_link_recv_bundle(buf); | 481 | tipc_link_recv_bundle(buf); |
482 | } else if (msg_user(msg) == MSG_FRAGMENTER) { | 482 | } else if (msg_user(msg) == MSG_FRAGMENTER) { |
483 | int ret = tipc_link_recv_fragment(&node->bclink.defragm, | 483 | int ret; |
484 | &buf, &msg); | 484 | ret = tipc_link_recv_fragment(&node->bclink.reasm_head, |
485 | if (ret < 0) | 485 | &node->bclink.reasm_tail, |
486 | &buf); | ||
487 | if (ret == LINK_REASM_ERROR) | ||
486 | goto unlock; | 488 | goto unlock; |
487 | spin_lock_bh(&bc_lock); | 489 | spin_lock_bh(&bc_lock); |
488 | bclink_accept_pkt(node, seqno); | 490 | bclink_accept_pkt(node, seqno); |
489 | bcl->stats.recv_fragments++; | 491 | bcl->stats.recv_fragments++; |
490 | if (ret > 0) | 492 | if (ret == LINK_REASM_COMPLETE) { |
491 | bcl->stats.recv_fragmented++; | 493 | bcl->stats.recv_fragmented++; |
494 | /* Point msg to inner header */ | ||
495 | msg = buf_msg(buf); | ||
496 | spin_unlock_bh(&bc_lock); | ||
497 | goto receive; | ||
498 | } | ||
492 | spin_unlock_bh(&bc_lock); | 499 | spin_unlock_bh(&bc_lock); |
493 | tipc_node_unlock(node); | 500 | tipc_node_unlock(node); |
494 | tipc_net_route_msg(buf); | ||
495 | } else if (msg_user(msg) == NAME_DISTRIBUTOR) { | 501 | } else if (msg_user(msg) == NAME_DISTRIBUTOR) { |
496 | spin_lock_bh(&bc_lock); | 502 | spin_lock_bh(&bc_lock); |
497 | bclink_accept_pkt(node, seqno); | 503 | bclink_accept_pkt(node, seqno); |
@@ -615,12 +621,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
615 | if (!p) | 621 | if (!p) |
616 | break; /* No more bearers to try */ | 622 | break; /* No more bearers to try */ |
617 | 623 | ||
618 | if (tipc_bearer_blocked(p)) { | ||
619 | if (!s || tipc_bearer_blocked(s)) | ||
620 | continue; /* Can't use either bearer */ | ||
621 | b = s; | ||
622 | } | ||
623 | |||
624 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, | 624 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, |
625 | &bcbearer->remains_new); | 625 | &bcbearer->remains_new); |
626 | if (bcbearer->remains_new.count == bcbearer->remains.count) | 626 | if (bcbearer->remains_new.count == bcbearer->remains.count) |
@@ -794,7 +794,7 @@ void tipc_bclink_init(void) | |||
794 | void tipc_bclink_stop(void) | 794 | void tipc_bclink_stop(void) |
795 | { | 795 | { |
796 | spin_lock_bh(&bc_lock); | 796 | spin_lock_bh(&bc_lock); |
797 | tipc_link_stop(bcl); | 797 | tipc_link_purge_queues(bcl); |
798 | spin_unlock_bh(&bc_lock); | 798 | spin_unlock_bh(&bc_lock); |
799 | 799 | ||
800 | memset(bclink, 0, sizeof(*bclink)); | 800 | memset(bclink, 0, sizeof(*bclink)); |
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 609c30c80816..a38c89969c68 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,7 +313,8 @@ 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); |
390 | res = m_ptr->enable_bearer(b_ptr); | 316 | b_ptr->media = m_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", |
393 | name, -res); | 320 | name, -res); |
@@ -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,25 +346,16 @@ exit: | |||
420 | } | 346 | } |
421 | 347 | ||
422 | /** | 348 | /** |
423 | * tipc_block_bearer - Block the bearer with the given name, and reset all its links | 349 | * tipc_reset_bearer - Reset all links established over this bearer |
424 | */ | 350 | */ |
425 | int tipc_block_bearer(const char *name) | 351 | static int tipc_reset_bearer(struct tipc_bearer *b_ptr) |
426 | { | 352 | { |
427 | struct tipc_bearer *b_ptr = NULL; | ||
428 | struct tipc_link *l_ptr; | 353 | struct tipc_link *l_ptr; |
429 | struct tipc_link *temp_l_ptr; | 354 | struct tipc_link *temp_l_ptr; |
430 | 355 | ||
431 | read_lock_bh(&tipc_net_lock); | 356 | read_lock_bh(&tipc_net_lock); |
432 | b_ptr = tipc_bearer_find(name); | 357 | pr_info("Resetting bearer <%s>\n", b_ptr->name); |
433 | if (!b_ptr) { | ||
434 | pr_warn("Attempt to block unknown bearer <%s>\n", name); | ||
435 | read_unlock_bh(&tipc_net_lock); | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | |||
439 | pr_info("Blocking bearer <%s>\n", name); | ||
440 | spin_lock_bh(&b_ptr->lock); | 358 | spin_lock_bh(&b_ptr->lock); |
441 | b_ptr->blocked = 1; | ||
442 | 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) { |
443 | struct tipc_node *n_ptr = l_ptr->owner; | 360 | struct tipc_node *n_ptr = l_ptr->owner; |
444 | 361 | ||
@@ -464,8 +381,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr) | |||
464 | 381 | ||
465 | pr_info("Disabling bearer <%s>\n", b_ptr->name); | 382 | pr_info("Disabling bearer <%s>\n", b_ptr->name); |
466 | spin_lock_bh(&b_ptr->lock); | 383 | spin_lock_bh(&b_ptr->lock); |
467 | b_ptr->blocked = 1; | 384 | b_ptr->media->disable_media(b_ptr); |
468 | b_ptr->media->disable_bearer(b_ptr); | ||
469 | 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) { |
470 | tipc_link_delete(l_ptr); | 386 | tipc_link_delete(l_ptr); |
471 | } | 387 | } |
@@ -498,6 +414,211 @@ int tipc_disable_bearer(const char *name) | |||
498 | } | 414 | } |
499 | 415 | ||
500 | 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 | dev_add_pack(&tipc_packet_type); | ||
614 | return register_netdevice_notifier(¬ifier); | ||
615 | } | ||
616 | |||
617 | void tipc_bearer_cleanup(void) | ||
618 | { | ||
619 | unregister_netdevice_notifier(¬ifier); | ||
620 | dev_remove_pack(&tipc_packet_type); | ||
621 | } | ||
501 | 622 | ||
502 | void tipc_bearer_stop(void) | 623 | void tipc_bearer_stop(void) |
503 | { | 624 | { |
@@ -507,5 +628,4 @@ void tipc_bearer_stop(void) | |||
507 | if (tipc_bearers[i].active) | 628 | if (tipc_bearers[i].active) |
508 | bearer_disable(&tipc_bearers[i]); | 629 | bearer_disable(&tipc_bearers[i]); |
509 | } | 630 | } |
510 | media_count = 0; | ||
511 | } | 631 | } |
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 09c869adcfcf..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,26 +73,26 @@ 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_bearer: routine which enables a bearer | 78 | * @enable_media: routine which enables a media |
79 | * @disable_bearer: routine which disables a bearer | 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 { |
91 | int (*send_msg)(struct sk_buff *buf, | 91 | int (*send_msg)(struct sk_buff *buf, |
92 | struct tipc_bearer *b_ptr, | 92 | struct tipc_bearer *b_ptr, |
93 | struct tipc_media_addr *dest); | 93 | struct tipc_media_addr *dest); |
94 | int (*enable_bearer)(struct tipc_bearer *b_ptr); | 94 | int (*enable_media)(struct tipc_bearer *b_ptr); |
95 | void (*disable_bearer)(struct tipc_bearer *b_ptr); | 95 | void (*disable_media)(struct tipc_bearer *b_ptr); |
96 | int (*addr2str)(struct tipc_media_addr *a, char *str_buf, int str_size); | 96 | int (*addr2str)(struct tipc_media_addr *a, char *str_buf, int str_size); |
97 | int (*addr2msg)(struct tipc_media_addr *a, char *msg_area); | 97 | int (*addr2msg)(struct tipc_media_addr *a, char *msg_area); |
98 | int (*msg2addr)(const struct tipc_bearer *b_ptr, | 98 | int (*msg2addr)(const struct tipc_bearer *b_ptr, |
@@ -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(const char *name); | ||
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/core.c b/net/tipc/core.c index fd4eeeaa972a..f9e88d8b04ca 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c | |||
@@ -82,8 +82,7 @@ struct sk_buff *tipc_buf_acquire(u32 size) | |||
82 | static void tipc_core_stop_net(void) | 82 | static void tipc_core_stop_net(void) |
83 | { | 83 | { |
84 | tipc_net_stop(); | 84 | tipc_net_stop(); |
85 | tipc_eth_media_stop(); | 85 | tipc_bearer_cleanup(); |
86 | tipc_ib_media_stop(); | ||
87 | } | 86 | } |
88 | 87 | ||
89 | /** | 88 | /** |
@@ -94,10 +93,7 @@ int tipc_core_start_net(unsigned long addr) | |||
94 | int res; | 93 | int res; |
95 | 94 | ||
96 | tipc_net_start(addr); | 95 | tipc_net_start(addr); |
97 | res = tipc_eth_media_start(); | 96 | res = tipc_bearer_setup(); |
98 | if (res < 0) | ||
99 | goto err; | ||
100 | res = tipc_ib_media_start(); | ||
101 | if (res < 0) | 97 | if (res < 0) |
102 | goto err; | 98 | goto err; |
103 | return res; | 99 | return res; |
@@ -113,7 +109,6 @@ err: | |||
113 | static void tipc_core_stop(void) | 109 | static void tipc_core_stop(void) |
114 | { | 110 | { |
115 | tipc_netlink_stop(); | 111 | tipc_netlink_stop(); |
116 | tipc_handler_stop(); | ||
117 | tipc_cfg_stop(); | 112 | tipc_cfg_stop(); |
118 | tipc_subscr_stop(); | 113 | tipc_subscr_stop(); |
119 | tipc_nametbl_stop(); | 114 | tipc_nametbl_stop(); |
@@ -146,9 +141,10 @@ static int tipc_core_start(void) | |||
146 | res = tipc_subscr_start(); | 141 | res = tipc_subscr_start(); |
147 | if (!res) | 142 | if (!res) |
148 | res = tipc_cfg_init(); | 143 | res = tipc_cfg_init(); |
149 | if (res) | 144 | if (res) { |
145 | tipc_handler_stop(); | ||
150 | tipc_core_stop(); | 146 | tipc_core_stop(); |
151 | 147 | } | |
152 | return res; | 148 | return res; |
153 | } | 149 | } |
154 | 150 | ||
@@ -178,6 +174,7 @@ static int __init tipc_init(void) | |||
178 | 174 | ||
179 | static void __exit tipc_exit(void) | 175 | static void __exit tipc_exit(void) |
180 | { | 176 | { |
177 | tipc_handler_stop(); | ||
181 | tipc_core_stop_net(); | 178 | tipc_core_stop_net(); |
182 | tipc_core_stop(); | 179 | tipc_core_stop(); |
183 | pr_info("Deactivated\n"); | 180 | pr_info("Deactivated\n"); |
diff --git a/net/tipc/core.h b/net/tipc/core.h index be72f8cebc53..1ff477b0450d 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,21 +90,21 @@ extern int tipc_random __read_mostly; | |||
90 | /* | 90 | /* |
91 | * Routines available to privileged subsystems | 91 | * Routines available to privileged subsystems |
92 | */ | 92 | */ |
93 | extern int tipc_core_start_net(unsigned long); | 93 | int tipc_core_start_net(unsigned long); |
94 | extern int tipc_handler_start(void); | 94 | int tipc_handler_start(void); |
95 | extern void tipc_handler_stop(void); | 95 | void tipc_handler_stop(void); |
96 | extern int tipc_netlink_start(void); | 96 | int tipc_netlink_start(void); |
97 | extern void tipc_netlink_stop(void); | 97 | void tipc_netlink_stop(void); |
98 | extern int tipc_socket_init(void); | 98 | int tipc_socket_init(void); |
99 | extern void tipc_socket_stop(void); | 99 | void tipc_socket_stop(void); |
100 | extern int tipc_sock_create_local(int type, struct socket **res); | 100 | int tipc_sock_create_local(int type, struct socket **res); |
101 | extern void tipc_sock_release_local(struct socket *sock); | 101 | void tipc_sock_release_local(struct socket *sock); |
102 | extern int tipc_sock_accept_local(struct socket *sock, | 102 | int tipc_sock_accept_local(struct socket *sock, struct socket **newsock, |
103 | struct socket **newsock, int flags); | 103 | int flags); |
104 | 104 | ||
105 | #ifdef CONFIG_SYSCTL | 105 | #ifdef CONFIG_SYSCTL |
106 | extern int tipc_register_sysctl(void); | 106 | int tipc_register_sysctl(void); |
107 | extern void tipc_unregister_sysctl(void); | 107 | void tipc_unregister_sysctl(void); |
108 | #else | 108 | #else |
109 | #define tipc_register_sysctl() 0 | 109 | #define tipc_register_sysctl() 0 |
110 | #define tipc_unregister_sysctl() | 110 | #define tipc_unregister_sysctl() |
@@ -201,6 +201,6 @@ static inline struct tipc_msg *buf_msg(struct sk_buff *skb) | |||
201 | return (struct tipc_msg *)skb->data; | 201 | return (struct tipc_msg *)skb->data; |
202 | } | 202 | } |
203 | 203 | ||
204 | extern struct sk_buff *tipc_buf_acquire(u32 size); | 204 | struct sk_buff *tipc_buf_acquire(u32 size); |
205 | 205 | ||
206 | #endif | 206 | #endif |
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 40ea40cf6204..67cf3f935dba 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c | |||
@@ -1,8 +1,8 @@ | |||
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, Wind River Systems | 5 | * Copyright (c) 2005-2008, 2011-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 |
@@ -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_BEARERS 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_bearer - 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_bearer { | ||
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_bearer eth_bearers[MAX_ETH_BEARERS]; | ||
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_bearer *)(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_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv; | ||
132 | |||
133 | if (!net_eq(dev_net(dev), &init_net)) { | ||
134 | kfree_skb(buf); | ||
135 | return 0; | ||
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 0; | ||
143 | } | ||
144 | } | ||
145 | kfree_skb(buf); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * setup_bearer - setup association between Ethernet bearer and interface | ||
151 | */ | ||
152 | static void setup_bearer(struct work_struct *work) | ||
153 | { | ||
154 | struct eth_bearer *eb_ptr = | ||
155 | container_of(work, struct eth_bearer, setup); | ||
156 | |||
157 | dev_add_pack(&eb_ptr->tipc_packet_type); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * enable_bearer - attach TIPC bearer to an Ethernet interface | ||
162 | */ | ||
163 | static int enable_bearer(struct tipc_bearer *tb_ptr) | ||
164 | { | ||
165 | struct net_device *dev; | ||
166 | struct eth_bearer *eb_ptr = ð_bearers[0]; | ||
167 | struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; | ||
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_bearer); | ||
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_bearer - 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_bearer(struct work_struct *work) | ||
213 | { | ||
214 | struct eth_bearer *eb_ptr = | ||
215 | container_of(work, struct eth_bearer, 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_bearer - 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_bearer(struct tipc_bearer *tb_ptr) | ||
230 | { | ||
231 | struct eth_bearer *eb_ptr = (struct eth_bearer *)tb_ptr->usr_handle; | ||
232 | |||
233 | eb_ptr->bearer = NULL; | ||
234 | INIT_WORK(&eb_ptr->cleanup, cleanup_bearer); | ||
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_bearer *eb_ptr = ð_bearers[0]; | ||
249 | struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; | ||
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->name); | ||
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->name); | ||
275 | break; | ||
276 | case NETDEV_CHANGEMTU: | ||
277 | case NETDEV_CHANGEADDR: | ||
278 | tipc_block_bearer(eb_ptr->bearer->name); | ||
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_bearer = enable_bearer, | 78 | .addr2str = tipc_eth_addr2str, |
331 | .disable_bearer = disable_bearer, | 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 b36f0fcd9bdf..e4bc8a296744 100644 --- a/net/tipc/handler.c +++ b/net/tipc/handler.c | |||
@@ -56,12 +56,13 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument) | |||
56 | { | 56 | { |
57 | struct queue_item *item; | 57 | struct queue_item *item; |
58 | 58 | ||
59 | spin_lock_bh(&qitem_lock); | ||
59 | if (!handler_enabled) { | 60 | if (!handler_enabled) { |
60 | pr_err("Signal request ignored by handler\n"); | 61 | pr_err("Signal request ignored by handler\n"); |
62 | spin_unlock_bh(&qitem_lock); | ||
61 | return -ENOPROTOOPT; | 63 | return -ENOPROTOOPT; |
62 | } | 64 | } |
63 | 65 | ||
64 | spin_lock_bh(&qitem_lock); | ||
65 | item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC); | 66 | item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC); |
66 | if (!item) { | 67 | if (!item) { |
67 | pr_err("Signal queue out of memory\n"); | 68 | pr_err("Signal queue out of memory\n"); |
@@ -112,10 +113,14 @@ void tipc_handler_stop(void) | |||
112 | struct list_head *l, *n; | 113 | struct list_head *l, *n; |
113 | struct queue_item *item; | 114 | struct queue_item *item; |
114 | 115 | ||
115 | if (!handler_enabled) | 116 | spin_lock_bh(&qitem_lock); |
117 | if (!handler_enabled) { | ||
118 | spin_unlock_bh(&qitem_lock); | ||
116 | return; | 119 | return; |
117 | 120 | } | |
118 | handler_enabled = 0; | 121 | handler_enabled = 0; |
122 | spin_unlock_bh(&qitem_lock); | ||
123 | |||
119 | tasklet_kill(&tipc_tasklet); | 124 | tasklet_kill(&tipc_tasklet); |
120 | 125 | ||
121 | spin_lock_bh(&qitem_lock); | 126 | spin_lock_bh(&qitem_lock); |
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index 9934a32bfa87..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_BEARERS 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_bearer - Infiniband bearer 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_bearer { | ||
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_bearer ib_bearers[MAX_IB_BEARERS]; | ||
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_bearer *)(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_bearer *ib_ptr = (struct ib_bearer *)pt->af_packet_priv; | ||
125 | |||
126 | if (!net_eq(dev_net(dev), &init_net)) { | ||
127 | kfree_skb(buf); | ||
128 | return 0; | ||
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 0; | ||
136 | } | ||
137 | } | ||
138 | kfree_skb(buf); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * setup_bearer - setup association between InfiniBand bearer and interface | ||
144 | */ | ||
145 | static void setup_bearer(struct work_struct *work) | ||
146 | { | ||
147 | struct ib_bearer *ib_ptr = | ||
148 | container_of(work, struct ib_bearer, setup); | ||
149 | |||
150 | dev_add_pack(&ib_ptr->tipc_packet_type); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * enable_bearer - attach TIPC bearer to an InfiniBand interface | ||
155 | */ | ||
156 | static int enable_bearer(struct tipc_bearer *tb_ptr) | ||
157 | { | ||
158 | struct net_device *dev; | ||
159 | struct ib_bearer *ib_ptr = &ib_bearers[0]; | ||
160 | struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS]; | ||
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_bearer); | ||
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_bearer *ib_ptr = | ||
208 | container_of(work, struct ib_bearer, 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_bearer - 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_bearer(struct tipc_bearer *tb_ptr) | ||
223 | { | ||
224 | struct ib_bearer *ib_ptr = (struct ib_bearer *)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_bearer *ib_ptr = &ib_bearers[0]; | ||
242 | struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS]; | ||
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->name); | ||
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->name); | ||
268 | break; | ||
269 | case NETDEV_CHANGEMTU: | ||
270 | case NETDEV_CHANGEADDR: | ||
271 | tipc_block_bearer(ib_ptr->bearer->name); | ||
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_bearer = enable_bearer, | 79 | .addr2str = tipc_ib_addr2str, |
327 | .disable_bearer = disable_bearer, | 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 0cc3d9015c5d..d4b5de41b682 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 | * |
@@ -75,34 +75,18 @@ static const char *link_unk_evt = "Unknown link event "; | |||
75 | */ | 75 | */ |
76 | #define START_CHANGEOVER 100000u | 76 | #define START_CHANGEOVER 100000u |
77 | 77 | ||
78 | /** | ||
79 | * struct tipc_link_name - deconstructed link name | ||
80 | * @addr_local: network address of node at this end | ||
81 | * @if_local: name of interface at this end | ||
82 | * @addr_peer: network address of node at far end | ||
83 | * @if_peer: name of interface at far end | ||
84 | */ | ||
85 | struct tipc_link_name { | ||
86 | u32 addr_local; | ||
87 | char if_local[TIPC_MAX_IF_NAME]; | ||
88 | u32 addr_peer; | ||
89 | char if_peer[TIPC_MAX_IF_NAME]; | ||
90 | }; | ||
91 | |||
92 | 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, |
93 | struct sk_buff *buf); | 79 | struct sk_buff *buf); |
94 | 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); |
95 | static int link_recv_changeover_msg(struct tipc_link **l_ptr, | 81 | static int tipc_link_tunnel_rcv(struct tipc_link **l_ptr, |
96 | struct sk_buff **buf); | 82 | struct sk_buff **buf); |
97 | 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); |
98 | static int link_send_sections_long(struct tipc_port *sender, | 84 | static int link_send_sections_long(struct tipc_port *sender, |
99 | struct iovec const *msg_sect, | 85 | struct iovec const *msg_sect, |
100 | u32 num_sect, unsigned int total_len, | 86 | unsigned int len, u32 destnode); |
101 | u32 destnode); | ||
102 | 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); |
103 | static void link_reset_statistics(struct tipc_link *l_ptr); | 88 | static void link_reset_statistics(struct tipc_link *l_ptr); |
104 | 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); |
105 | static void link_start(struct tipc_link *l_ptr); | ||
106 | 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); |
107 | static void tipc_link_send_sync(struct tipc_link *l); | 91 | static void tipc_link_send_sync(struct tipc_link *l); |
108 | 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); |
@@ -161,72 +145,6 @@ int tipc_link_is_active(struct tipc_link *l_ptr) | |||
161 | } | 145 | } |
162 | 146 | ||
163 | /** | 147 | /** |
164 | * link_name_validate - validate & (optionally) deconstruct tipc_link name | ||
165 | * @name: ptr to link name string | ||
166 | * @name_parts: ptr to area for link name components (or NULL if not needed) | ||
167 | * | ||
168 | * Returns 1 if link name is valid, otherwise 0. | ||
169 | */ | ||
170 | static int link_name_validate(const char *name, | ||
171 | struct tipc_link_name *name_parts) | ||
172 | { | ||
173 | char name_copy[TIPC_MAX_LINK_NAME]; | ||
174 | char *addr_local; | ||
175 | char *if_local; | ||
176 | char *addr_peer; | ||
177 | char *if_peer; | ||
178 | char dummy; | ||
179 | u32 z_local, c_local, n_local; | ||
180 | u32 z_peer, c_peer, n_peer; | ||
181 | u32 if_local_len; | ||
182 | u32 if_peer_len; | ||
183 | |||
184 | /* copy link name & ensure length is OK */ | ||
185 | name_copy[TIPC_MAX_LINK_NAME - 1] = 0; | ||
186 | /* need above in case non-Posix strncpy() doesn't pad with nulls */ | ||
187 | strncpy(name_copy, name, TIPC_MAX_LINK_NAME); | ||
188 | if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0) | ||
189 | return 0; | ||
190 | |||
191 | /* ensure all component parts of link name are present */ | ||
192 | addr_local = name_copy; | ||
193 | if_local = strchr(addr_local, ':'); | ||
194 | if (if_local == NULL) | ||
195 | return 0; | ||
196 | *(if_local++) = 0; | ||
197 | addr_peer = strchr(if_local, '-'); | ||
198 | if (addr_peer == NULL) | ||
199 | return 0; | ||
200 | *(addr_peer++) = 0; | ||
201 | if_local_len = addr_peer - if_local; | ||
202 | if_peer = strchr(addr_peer, ':'); | ||
203 | if (if_peer == NULL) | ||
204 | return 0; | ||
205 | *(if_peer++) = 0; | ||
206 | if_peer_len = strlen(if_peer) + 1; | ||
207 | |||
208 | /* validate component parts of link name */ | ||
209 | if ((sscanf(addr_local, "%u.%u.%u%c", | ||
210 | &z_local, &c_local, &n_local, &dummy) != 3) || | ||
211 | (sscanf(addr_peer, "%u.%u.%u%c", | ||
212 | &z_peer, &c_peer, &n_peer, &dummy) != 3) || | ||
213 | (z_local > 255) || (c_local > 4095) || (n_local > 4095) || | ||
214 | (z_peer > 255) || (c_peer > 4095) || (n_peer > 4095) || | ||
215 | (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) || | ||
216 | (if_peer_len <= 1) || (if_peer_len > TIPC_MAX_IF_NAME)) | ||
217 | return 0; | ||
218 | |||
219 | /* return link name components, if necessary */ | ||
220 | if (name_parts) { | ||
221 | name_parts->addr_local = tipc_addr(z_local, c_local, n_local); | ||
222 | strcpy(name_parts->if_local, if_local); | ||
223 | name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer); | ||
224 | strcpy(name_parts->if_peer, if_peer); | ||
225 | } | ||
226 | return 1; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * link_timeout - handle expiration of link timer | 148 | * link_timeout - handle expiration of link timer |
231 | * @l_ptr: pointer to link | 149 | * @l_ptr: pointer to link |
232 | * | 150 | * |
@@ -359,9 +277,11 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
359 | 277 | ||
360 | tipc_node_attach_link(n_ptr, l_ptr); | 278 | tipc_node_attach_link(n_ptr, l_ptr); |
361 | 279 | ||
362 | 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); | ||
363 | list_add_tail(&l_ptr->link_list, &b_ptr->links); | 282 | list_add_tail(&l_ptr->link_list, &b_ptr->links); |
364 | tipc_k_signal((Handler)link_start, (unsigned long)l_ptr); | 283 | |
284 | link_state_event(l_ptr, STARTING_EVT); | ||
365 | 285 | ||
366 | return l_ptr; | 286 | return l_ptr; |
367 | } | 287 | } |
@@ -386,19 +306,13 @@ void tipc_link_delete(struct tipc_link *l_ptr) | |||
386 | tipc_node_lock(l_ptr->owner); | 306 | tipc_node_lock(l_ptr->owner); |
387 | tipc_link_reset(l_ptr); | 307 | tipc_link_reset(l_ptr); |
388 | tipc_node_detach_link(l_ptr->owner, l_ptr); | 308 | tipc_node_detach_link(l_ptr->owner, l_ptr); |
389 | tipc_link_stop(l_ptr); | 309 | tipc_link_purge_queues(l_ptr); |
390 | list_del_init(&l_ptr->link_list); | 310 | list_del_init(&l_ptr->link_list); |
391 | tipc_node_unlock(l_ptr->owner); | 311 | tipc_node_unlock(l_ptr->owner); |
392 | k_term_timer(&l_ptr->timer); | 312 | k_term_timer(&l_ptr->timer); |
393 | kfree(l_ptr); | 313 | kfree(l_ptr); |
394 | } | 314 | } |
395 | 315 | ||
396 | static void link_start(struct tipc_link *l_ptr) | ||
397 | { | ||
398 | tipc_node_lock(l_ptr->owner); | ||
399 | link_state_event(l_ptr, STARTING_EVT); | ||
400 | tipc_node_unlock(l_ptr->owner); | ||
401 | } | ||
402 | 316 | ||
403 | /** | 317 | /** |
404 | * link_schedule_port - schedule port for deferred sending | 318 | * link_schedule_port - schedule port for deferred sending |
@@ -467,14 +381,7 @@ exit: | |||
467 | */ | 381 | */ |
468 | static void link_release_outqueue(struct tipc_link *l_ptr) | 382 | static void link_release_outqueue(struct tipc_link *l_ptr) |
469 | { | 383 | { |
470 | struct sk_buff *buf = l_ptr->first_out; | 384 | kfree_skb_list(l_ptr->first_out); |
471 | struct sk_buff *next; | ||
472 | |||
473 | while (buf) { | ||
474 | next = buf->next; | ||
475 | kfree_skb(buf); | ||
476 | buf = next; | ||
477 | } | ||
478 | l_ptr->first_out = NULL; | 385 | l_ptr->first_out = NULL; |
479 | l_ptr->out_queue_size = 0; | 386 | l_ptr->out_queue_size = 0; |
480 | } | 387 | } |
@@ -485,49 +392,26 @@ static void link_release_outqueue(struct tipc_link *l_ptr) | |||
485 | */ | 392 | */ |
486 | void tipc_link_reset_fragments(struct tipc_link *l_ptr) | 393 | void tipc_link_reset_fragments(struct tipc_link *l_ptr) |
487 | { | 394 | { |
488 | struct sk_buff *buf = l_ptr->defragm_buf; | 395 | kfree_skb(l_ptr->reasm_head); |
489 | struct sk_buff *next; | 396 | l_ptr->reasm_head = NULL; |
490 | 397 | l_ptr->reasm_tail = NULL; | |
491 | while (buf) { | ||
492 | next = buf->next; | ||
493 | kfree_skb(buf); | ||
494 | buf = next; | ||
495 | } | ||
496 | l_ptr->defragm_buf = NULL; | ||
497 | } | 398 | } |
498 | 399 | ||
499 | /** | 400 | /** |
500 | * tipc_link_stop - purge all inbound and outbound messages associated with link | 401 | * tipc_link_purge_queues - purge all pkt queues associated with link |
501 | * @l_ptr: pointer to link | 402 | * @l_ptr: pointer to link |
502 | */ | 403 | */ |
503 | void tipc_link_stop(struct tipc_link *l_ptr) | 404 | void tipc_link_purge_queues(struct tipc_link *l_ptr) |
504 | { | 405 | { |
505 | struct sk_buff *buf; | 406 | kfree_skb_list(l_ptr->oldest_deferred_in); |
506 | struct sk_buff *next; | 407 | kfree_skb_list(l_ptr->first_out); |
507 | |||
508 | buf = l_ptr->oldest_deferred_in; | ||
509 | while (buf) { | ||
510 | next = buf->next; | ||
511 | kfree_skb(buf); | ||
512 | buf = next; | ||
513 | } | ||
514 | |||
515 | buf = l_ptr->first_out; | ||
516 | while (buf) { | ||
517 | next = buf->next; | ||
518 | kfree_skb(buf); | ||
519 | buf = next; | ||
520 | } | ||
521 | |||
522 | tipc_link_reset_fragments(l_ptr); | 408 | tipc_link_reset_fragments(l_ptr); |
523 | |||
524 | kfree_skb(l_ptr->proto_msg_queue); | 409 | kfree_skb(l_ptr->proto_msg_queue); |
525 | l_ptr->proto_msg_queue = NULL; | 410 | l_ptr->proto_msg_queue = NULL; |
526 | } | 411 | } |
527 | 412 | ||
528 | void tipc_link_reset(struct tipc_link *l_ptr) | 413 | void tipc_link_reset(struct tipc_link *l_ptr) |
529 | { | 414 | { |
530 | struct sk_buff *buf; | ||
531 | u32 prev_state = l_ptr->state; | 415 | u32 prev_state = l_ptr->state; |
532 | u32 checkpoint = l_ptr->next_in_no; | 416 | u32 checkpoint = l_ptr->next_in_no; |
533 | int was_active_link = tipc_link_is_active(l_ptr); | 417 | int was_active_link = tipc_link_is_active(l_ptr); |
@@ -548,8 +432,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
548 | tipc_node_link_down(l_ptr->owner, l_ptr); | 432 | tipc_node_link_down(l_ptr->owner, l_ptr); |
549 | tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr); | 433 | tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr); |
550 | 434 | ||
551 | if (was_active_link && tipc_node_active_links(l_ptr->owner) && | 435 | if (was_active_link && tipc_node_active_links(l_ptr->owner)) { |
552 | l_ptr->owner->permit_changeover) { | ||
553 | l_ptr->reset_checkpoint = checkpoint; | 436 | l_ptr->reset_checkpoint = checkpoint; |
554 | l_ptr->exp_msg_count = START_CHANGEOVER; | 437 | l_ptr->exp_msg_count = START_CHANGEOVER; |
555 | } | 438 | } |
@@ -558,12 +441,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
558 | link_release_outqueue(l_ptr); | 441 | link_release_outqueue(l_ptr); |
559 | kfree_skb(l_ptr->proto_msg_queue); | 442 | kfree_skb(l_ptr->proto_msg_queue); |
560 | l_ptr->proto_msg_queue = NULL; | 443 | l_ptr->proto_msg_queue = NULL; |
561 | buf = l_ptr->oldest_deferred_in; | 444 | kfree_skb_list(l_ptr->oldest_deferred_in); |
562 | while (buf) { | ||
563 | struct sk_buff *next = buf->next; | ||
564 | kfree_skb(buf); | ||
565 | buf = next; | ||
566 | } | ||
567 | if (!list_empty(&l_ptr->waiting_ports)) | 445 | if (!list_empty(&l_ptr->waiting_ports)) |
568 | tipc_link_wakeup_ports(l_ptr, 1); | 446 | tipc_link_wakeup_ports(l_ptr, 1); |
569 | 447 | ||
@@ -604,10 +482,11 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) | |||
604 | if (!l_ptr->started && (event != STARTING_EVT)) | 482 | if (!l_ptr->started && (event != STARTING_EVT)) |
605 | return; /* Not yet. */ | 483 | return; /* Not yet. */ |
606 | 484 | ||
607 | if (link_blocked(l_ptr)) { | 485 | /* Check whether changeover is going on */ |
486 | if (l_ptr->exp_msg_count) { | ||
608 | if (event == TIMEOUT_EVT) | 487 | if (event == TIMEOUT_EVT) |
609 | link_set_timer(l_ptr, cont_intv); | 488 | link_set_timer(l_ptr, cont_intv); |
610 | return; /* Changeover going on */ | 489 | return; |
611 | } | 490 | } |
612 | 491 | ||
613 | switch (l_ptr->state) { | 492 | switch (l_ptr->state) { |
@@ -877,8 +756,7 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
877 | return link_send_long_buf(l_ptr, buf); | 756 | return link_send_long_buf(l_ptr, buf); |
878 | 757 | ||
879 | /* Packet can be queued or sent. */ | 758 | /* Packet can be queued or sent. */ |
880 | if (likely(!tipc_bearer_blocked(l_ptr->b_ptr) && | 759 | if (likely(!link_congested(l_ptr))) { |
881 | !link_congested(l_ptr))) { | ||
882 | link_add_to_outqueue(l_ptr, buf, msg); | 760 | link_add_to_outqueue(l_ptr, buf, msg); |
883 | 761 | ||
884 | 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); |
@@ -1044,14 +922,13 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
1044 | 922 | ||
1045 | if (likely(!link_congested(l_ptr))) { | 923 | if (likely(!link_congested(l_ptr))) { |
1046 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { | 924 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { |
1047 | if (likely(!tipc_bearer_blocked(l_ptr->b_ptr))) { | 925 | link_add_to_outqueue(l_ptr, buf, msg); |
1048 | link_add_to_outqueue(l_ptr, buf, msg); | 926 | tipc_bearer_send(l_ptr->b_ptr, buf, |
1049 | tipc_bearer_send(l_ptr->b_ptr, buf, | 927 | &l_ptr->media_addr); |
1050 | &l_ptr->media_addr); | 928 | l_ptr->unacked_window = 0; |
1051 | l_ptr->unacked_window = 0; | 929 | return res; |
1052 | return res; | 930 | } |
1053 | } | 931 | else |
1054 | } else | ||
1055 | *used_max_pkt = l_ptr->max_pkt; | 932 | *used_max_pkt = l_ptr->max_pkt; |
1056 | } | 933 | } |
1057 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ | 934 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ |
@@ -1065,8 +942,7 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
1065 | */ | 942 | */ |
1066 | int tipc_link_send_sections_fast(struct tipc_port *sender, | 943 | int tipc_link_send_sections_fast(struct tipc_port *sender, |
1067 | struct iovec const *msg_sect, | 944 | struct iovec const *msg_sect, |
1068 | const u32 num_sect, unsigned int total_len, | 945 | unsigned int len, u32 destaddr) |
1069 | u32 destaddr) | ||
1070 | { | 946 | { |
1071 | struct tipc_msg *hdr = &sender->phdr; | 947 | struct tipc_msg *hdr = &sender->phdr; |
1072 | struct tipc_link *l_ptr; | 948 | struct tipc_link *l_ptr; |
@@ -1080,8 +956,7 @@ again: | |||
1080 | * Try building message using port's max_pkt hint. | 956 | * Try building message using port's max_pkt hint. |
1081 | * (Must not hold any locks while building message.) | 957 | * (Must not hold any locks while building message.) |
1082 | */ | 958 | */ |
1083 | res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, | 959 | res = tipc_msg_build(hdr, msg_sect, len, sender->max_pkt, &buf); |
1084 | sender->max_pkt, &buf); | ||
1085 | /* Exit if build request was invalid */ | 960 | /* Exit if build request was invalid */ |
1086 | if (unlikely(res < 0)) | 961 | if (unlikely(res < 0)) |
1087 | return res; | 962 | return res; |
@@ -1102,8 +977,7 @@ exit: | |||
1102 | } | 977 | } |
1103 | 978 | ||
1104 | /* Exit if link (or bearer) is congested */ | 979 | /* Exit if link (or bearer) is congested */ |
1105 | if (link_congested(l_ptr) || | 980 | if (link_congested(l_ptr)) { |
1106 | tipc_bearer_blocked(l_ptr->b_ptr)) { | ||
1107 | res = link_schedule_port(l_ptr, | 981 | res = link_schedule_port(l_ptr, |
1108 | sender->ref, res); | 982 | sender->ref, res); |
1109 | goto exit; | 983 | goto exit; |
@@ -1121,8 +995,7 @@ exit: | |||
1121 | if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) | 995 | if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) |
1122 | goto again; | 996 | goto again; |
1123 | 997 | ||
1124 | return link_send_sections_long(sender, msg_sect, | 998 | return link_send_sections_long(sender, msg_sect, len, |
1125 | num_sect, total_len, | ||
1126 | destaddr); | 999 | destaddr); |
1127 | } | 1000 | } |
1128 | tipc_node_unlock(node); | 1001 | tipc_node_unlock(node); |
@@ -1133,8 +1006,8 @@ exit: | |||
1133 | if (buf) | 1006 | if (buf) |
1134 | return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); | 1007 | return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); |
1135 | if (res >= 0) | 1008 | if (res >= 0) |
1136 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, | 1009 | return tipc_port_reject_sections(sender, hdr, msg_sect, |
1137 | total_len, TIPC_ERR_NO_NODE); | 1010 | len, TIPC_ERR_NO_NODE); |
1138 | return res; | 1011 | return res; |
1139 | } | 1012 | } |
1140 | 1013 | ||
@@ -1154,18 +1027,17 @@ exit: | |||
1154 | */ | 1027 | */ |
1155 | static int link_send_sections_long(struct tipc_port *sender, | 1028 | static int link_send_sections_long(struct tipc_port *sender, |
1156 | struct iovec const *msg_sect, | 1029 | struct iovec const *msg_sect, |
1157 | u32 num_sect, unsigned int total_len, | 1030 | unsigned int len, u32 destaddr) |
1158 | u32 destaddr) | ||
1159 | { | 1031 | { |
1160 | struct tipc_link *l_ptr; | 1032 | struct tipc_link *l_ptr; |
1161 | struct tipc_node *node; | 1033 | struct tipc_node *node; |
1162 | struct tipc_msg *hdr = &sender->phdr; | 1034 | struct tipc_msg *hdr = &sender->phdr; |
1163 | u32 dsz = total_len; | 1035 | u32 dsz = len; |
1164 | u32 max_pkt, fragm_sz, rest; | 1036 | u32 max_pkt, fragm_sz, rest; |
1165 | struct tipc_msg fragm_hdr; | 1037 | struct tipc_msg fragm_hdr; |
1166 | struct sk_buff *buf, *buf_chain, *prev; | 1038 | struct sk_buff *buf, *buf_chain, *prev; |
1167 | u32 fragm_crs, fragm_rest, hsz, sect_rest; | 1039 | u32 fragm_crs, fragm_rest, hsz, sect_rest; |
1168 | const unchar *sect_crs; | 1040 | const unchar __user *sect_crs; |
1169 | int curr_sect; | 1041 | int curr_sect; |
1170 | u32 fragm_no; | 1042 | u32 fragm_no; |
1171 | int res = 0; | 1043 | int res = 0; |
@@ -1207,7 +1079,7 @@ again: | |||
1207 | 1079 | ||
1208 | if (!sect_rest) { | 1080 | if (!sect_rest) { |
1209 | sect_rest = msg_sect[++curr_sect].iov_len; | 1081 | sect_rest = msg_sect[++curr_sect].iov_len; |
1210 | sect_crs = (const unchar *)msg_sect[curr_sect].iov_base; | 1082 | sect_crs = msg_sect[curr_sect].iov_base; |
1211 | } | 1083 | } |
1212 | 1084 | ||
1213 | if (sect_rest < fragm_rest) | 1085 | if (sect_rest < fragm_rest) |
@@ -1218,10 +1090,7 @@ again: | |||
1218 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { | 1090 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { |
1219 | res = -EFAULT; | 1091 | res = -EFAULT; |
1220 | error: | 1092 | error: |
1221 | for (; buf_chain; buf_chain = buf) { | 1093 | kfree_skb_list(buf_chain); |
1222 | buf = buf_chain->next; | ||
1223 | kfree_skb(buf_chain); | ||
1224 | } | ||
1225 | return res; | 1094 | return res; |
1226 | } | 1095 | } |
1227 | sect_crs += sz; | 1096 | sect_crs += sz; |
@@ -1271,20 +1140,14 @@ error: | |||
1271 | if (l_ptr->max_pkt < max_pkt) { | 1140 | if (l_ptr->max_pkt < max_pkt) { |
1272 | sender->max_pkt = l_ptr->max_pkt; | 1141 | sender->max_pkt = l_ptr->max_pkt; |
1273 | tipc_node_unlock(node); | 1142 | tipc_node_unlock(node); |
1274 | for (; buf_chain; buf_chain = buf) { | 1143 | kfree_skb_list(buf_chain); |
1275 | buf = buf_chain->next; | ||
1276 | kfree_skb(buf_chain); | ||
1277 | } | ||
1278 | goto again; | 1144 | goto again; |
1279 | } | 1145 | } |
1280 | } else { | 1146 | } else { |
1281 | reject: | 1147 | reject: |
1282 | for (; buf_chain; buf_chain = buf) { | 1148 | kfree_skb_list(buf_chain); |
1283 | buf = buf_chain->next; | 1149 | return tipc_port_reject_sections(sender, hdr, msg_sect, |
1284 | kfree_skb(buf_chain); | 1150 | len, TIPC_ERR_NO_NODE); |
1285 | } | ||
1286 | return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, | ||
1287 | total_len, TIPC_ERR_NO_NODE); | ||
1288 | } | 1151 | } |
1289 | 1152 | ||
1290 | /* Append chain of fragments to send queue & send them */ | 1153 | /* Append chain of fragments to send queue & send them */ |
@@ -1300,7 +1163,7 @@ reject: | |||
1300 | /* | 1163 | /* |
1301 | * tipc_link_push_packet: Push one unsent packet to the media | 1164 | * tipc_link_push_packet: Push one unsent packet to the media |
1302 | */ | 1165 | */ |
1303 | u32 tipc_link_push_packet(struct tipc_link *l_ptr) | 1166 | static u32 tipc_link_push_packet(struct tipc_link *l_ptr) |
1304 | { | 1167 | { |
1305 | struct sk_buff *buf = l_ptr->first_out; | 1168 | struct sk_buff *buf = l_ptr->first_out; |
1306 | u32 r_q_size = l_ptr->retransm_queue_size; | 1169 | u32 r_q_size = l_ptr->retransm_queue_size; |
@@ -1372,9 +1235,6 @@ void tipc_link_push_queue(struct tipc_link *l_ptr) | |||
1372 | { | 1235 | { |
1373 | u32 res; | 1236 | u32 res; |
1374 | 1237 | ||
1375 | if (tipc_bearer_blocked(l_ptr->b_ptr)) | ||
1376 | return; | ||
1377 | |||
1378 | do { | 1238 | do { |
1379 | res = tipc_link_push_packet(l_ptr); | 1239 | res = tipc_link_push_packet(l_ptr); |
1380 | } while (!res); | 1240 | } while (!res); |
@@ -1461,26 +1321,15 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *buf, | |||
1461 | 1321 | ||
1462 | msg = buf_msg(buf); | 1322 | msg = buf_msg(buf); |
1463 | 1323 | ||
1464 | if (tipc_bearer_blocked(l_ptr->b_ptr)) { | 1324 | /* Detect repeated retransmit failures */ |
1465 | if (l_ptr->retransm_queue_size == 0) { | 1325 | if (l_ptr->last_retransmitted == msg_seqno(msg)) { |
1466 | l_ptr->retransm_queue_head = msg_seqno(msg); | 1326 | if (++l_ptr->stale_count > 100) { |
1467 | l_ptr->retransm_queue_size = retransmits; | 1327 | link_retransmit_failure(l_ptr, buf); |
1468 | } else { | 1328 | return; |
1469 | pr_err("Unexpected retransmit on link %s (qsize=%d)\n", | ||
1470 | l_ptr->name, l_ptr->retransm_queue_size); | ||
1471 | } | 1329 | } |
1472 | return; | ||
1473 | } else { | 1330 | } else { |
1474 | /* Detect repeated retransmit failures on unblocked bearer */ | 1331 | l_ptr->last_retransmitted = msg_seqno(msg); |
1475 | if (l_ptr->last_retransmitted == msg_seqno(msg)) { | 1332 | l_ptr->stale_count = 1; |
1476 | if (++l_ptr->stale_count > 100) { | ||
1477 | link_retransmit_failure(l_ptr, buf); | ||
1478 | return; | ||
1479 | } | ||
1480 | } else { | ||
1481 | l_ptr->last_retransmitted = msg_seqno(msg); | ||
1482 | l_ptr->stale_count = 1; | ||
1483 | } | ||
1484 | } | 1333 | } |
1485 | 1334 | ||
1486 | while (retransmits && (buf != l_ptr->next_out) && buf) { | 1335 | while (retransmits && (buf != l_ptr->next_out) && buf) { |
@@ -1567,14 +1416,14 @@ static int link_recv_buf_validate(struct sk_buff *buf) | |||
1567 | } | 1416 | } |
1568 | 1417 | ||
1569 | /** | 1418 | /** |
1570 | * tipc_recv_msg - process TIPC messages arriving from off-node | 1419 | * tipc_rcv - process TIPC packets/messages arriving from off-node |
1571 | * @head: pointer to message buffer chain | 1420 | * @head: pointer to message buffer chain |
1572 | * @tb_ptr: pointer to bearer message arrived on | 1421 | * @tb_ptr: pointer to bearer message arrived on |
1573 | * | 1422 | * |
1574 | * Invoked with no locks held. Bearer pointer must point to a valid bearer | 1423 | * Invoked with no locks held. Bearer pointer must point to a valid bearer |
1575 | * structure (i.e. cannot be NULL), but bearer can be inactive. | 1424 | * structure (i.e. cannot be NULL), but bearer can be inactive. |
1576 | */ | 1425 | */ |
1577 | void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | 1426 | void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) |
1578 | { | 1427 | { |
1579 | read_lock_bh(&tipc_net_lock); | 1428 | read_lock_bh(&tipc_net_lock); |
1580 | while (head) { | 1429 | while (head) { |
@@ -1589,18 +1438,19 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1589 | int type; | 1438 | int type; |
1590 | 1439 | ||
1591 | head = head->next; | 1440 | head = head->next; |
1441 | buf->next = NULL; | ||
1592 | 1442 | ||
1593 | /* Ensure bearer is still enabled */ | 1443 | /* Ensure bearer is still enabled */ |
1594 | if (unlikely(!b_ptr->active)) | 1444 | if (unlikely(!b_ptr->active)) |
1595 | goto cont; | 1445 | goto discard; |
1596 | 1446 | ||
1597 | /* Ensure message is well-formed */ | 1447 | /* Ensure message is well-formed */ |
1598 | if (unlikely(!link_recv_buf_validate(buf))) | 1448 | if (unlikely(!link_recv_buf_validate(buf))) |
1599 | goto cont; | 1449 | goto discard; |
1600 | 1450 | ||
1601 | /* Ensure message data is a single contiguous unit */ | 1451 | /* Ensure message data is a single contiguous unit */ |
1602 | if (unlikely(skb_linearize(buf))) | 1452 | if (unlikely(skb_linearize(buf))) |
1603 | goto cont; | 1453 | goto discard; |
1604 | 1454 | ||
1605 | /* Handle arrival of a non-unicast link message */ | 1455 | /* Handle arrival of a non-unicast link message */ |
1606 | msg = buf_msg(buf); | 1456 | msg = buf_msg(buf); |
@@ -1616,20 +1466,18 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1616 | /* Discard unicast link messages destined for another node */ | 1466 | /* Discard unicast link messages destined for another node */ |
1617 | if (unlikely(!msg_short(msg) && | 1467 | if (unlikely(!msg_short(msg) && |
1618 | (msg_destnode(msg) != tipc_own_addr))) | 1468 | (msg_destnode(msg) != tipc_own_addr))) |
1619 | goto cont; | 1469 | goto discard; |
1620 | 1470 | ||
1621 | /* Locate neighboring node that sent message */ | 1471 | /* Locate neighboring node that sent message */ |
1622 | n_ptr = tipc_node_find(msg_prevnode(msg)); | 1472 | n_ptr = tipc_node_find(msg_prevnode(msg)); |
1623 | if (unlikely(!n_ptr)) | 1473 | if (unlikely(!n_ptr)) |
1624 | goto cont; | 1474 | goto discard; |
1625 | tipc_node_lock(n_ptr); | 1475 | tipc_node_lock(n_ptr); |
1626 | 1476 | ||
1627 | /* Locate unicast link endpoint that should handle message */ | 1477 | /* Locate unicast link endpoint that should handle message */ |
1628 | l_ptr = n_ptr->links[b_ptr->identity]; | 1478 | l_ptr = n_ptr->links[b_ptr->identity]; |
1629 | if (unlikely(!l_ptr)) { | 1479 | if (unlikely(!l_ptr)) |
1630 | tipc_node_unlock(n_ptr); | 1480 | goto unlock_discard; |
1631 | goto cont; | ||
1632 | } | ||
1633 | 1481 | ||
1634 | /* Verify that communication with node is currently allowed */ | 1482 | /* Verify that communication with node is currently allowed */ |
1635 | if ((n_ptr->block_setup & WAIT_PEER_DOWN) && | 1483 | if ((n_ptr->block_setup & WAIT_PEER_DOWN) && |
@@ -1639,10 +1487,8 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1639 | !msg_redundant_link(msg)) | 1487 | !msg_redundant_link(msg)) |
1640 | n_ptr->block_setup &= ~WAIT_PEER_DOWN; | 1488 | n_ptr->block_setup &= ~WAIT_PEER_DOWN; |
1641 | 1489 | ||
1642 | if (n_ptr->block_setup) { | 1490 | if (n_ptr->block_setup) |
1643 | tipc_node_unlock(n_ptr); | 1491 | goto unlock_discard; |
1644 | goto cont; | ||
1645 | } | ||
1646 | 1492 | ||
1647 | /* Validate message sequence number info */ | 1493 | /* Validate message sequence number info */ |
1648 | seq_no = msg_seqno(msg); | 1494 | seq_no = msg_seqno(msg); |
@@ -1678,98 +1524,100 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1678 | 1524 | ||
1679 | /* Now (finally!) process the incoming message */ | 1525 | /* Now (finally!) process the incoming message */ |
1680 | protocol_check: | 1526 | protocol_check: |
1681 | if (likely(link_working_working(l_ptr))) { | 1527 | if (unlikely(!link_working_working(l_ptr))) { |
1682 | if (likely(seq_no == mod(l_ptr->next_in_no))) { | 1528 | if (msg_user(msg) == LINK_PROTOCOL) { |
1683 | l_ptr->next_in_no++; | 1529 | link_recv_proto_msg(l_ptr, buf); |
1684 | if (unlikely(l_ptr->oldest_deferred_in)) | 1530 | head = link_insert_deferred_queue(l_ptr, head); |
1685 | head = link_insert_deferred_queue(l_ptr, | ||
1686 | head); | ||
1687 | deliver: | ||
1688 | if (likely(msg_isdata(msg))) { | ||
1689 | tipc_node_unlock(n_ptr); | ||
1690 | tipc_port_recv_msg(buf); | ||
1691 | continue; | ||
1692 | } | ||
1693 | switch (msg_user(msg)) { | ||
1694 | int ret; | ||
1695 | case MSG_BUNDLER: | ||
1696 | l_ptr->stats.recv_bundles++; | ||
1697 | l_ptr->stats.recv_bundled += | ||
1698 | msg_msgcnt(msg); | ||
1699 | tipc_node_unlock(n_ptr); | ||
1700 | tipc_link_recv_bundle(buf); | ||
1701 | continue; | ||
1702 | case NAME_DISTRIBUTOR: | ||
1703 | n_ptr->bclink.recv_permitted = true; | ||
1704 | tipc_node_unlock(n_ptr); | ||
1705 | tipc_named_recv(buf); | ||
1706 | continue; | ||
1707 | case BCAST_PROTOCOL: | ||
1708 | tipc_link_recv_sync(n_ptr, buf); | ||
1709 | tipc_node_unlock(n_ptr); | ||
1710 | continue; | ||
1711 | case CONN_MANAGER: | ||
1712 | tipc_node_unlock(n_ptr); | ||
1713 | tipc_port_recv_proto_msg(buf); | ||
1714 | continue; | ||
1715 | case MSG_FRAGMENTER: | ||
1716 | l_ptr->stats.recv_fragments++; | ||
1717 | ret = tipc_link_recv_fragment( | ||
1718 | &l_ptr->defragm_buf, | ||
1719 | &buf, &msg); | ||
1720 | if (ret == 1) { | ||
1721 | l_ptr->stats.recv_fragmented++; | ||
1722 | goto deliver; | ||
1723 | } | ||
1724 | if (ret == -1) | ||
1725 | l_ptr->next_in_no--; | ||
1726 | break; | ||
1727 | case CHANGEOVER_PROTOCOL: | ||
1728 | type = msg_type(msg); | ||
1729 | if (link_recv_changeover_msg(&l_ptr, | ||
1730 | &buf)) { | ||
1731 | msg = buf_msg(buf); | ||
1732 | seq_no = msg_seqno(msg); | ||
1733 | if (type == ORIGINAL_MSG) | ||
1734 | goto deliver; | ||
1735 | goto protocol_check; | ||
1736 | } | ||
1737 | break; | ||
1738 | default: | ||
1739 | kfree_skb(buf); | ||
1740 | buf = NULL; | ||
1741 | break; | ||
1742 | } | ||
1743 | tipc_node_unlock(n_ptr); | 1531 | tipc_node_unlock(n_ptr); |
1744 | tipc_net_route_msg(buf); | ||
1745 | continue; | 1532 | continue; |
1746 | } | 1533 | } |
1534 | |||
1535 | /* Traffic message. Conditionally activate link */ | ||
1536 | link_state_event(l_ptr, TRAFFIC_MSG_EVT); | ||
1537 | |||
1538 | if (link_working_working(l_ptr)) { | ||
1539 | /* Re-insert buffer in front of queue */ | ||
1540 | buf->next = head; | ||
1541 | head = buf; | ||
1542 | tipc_node_unlock(n_ptr); | ||
1543 | continue; | ||
1544 | } | ||
1545 | goto unlock_discard; | ||
1546 | } | ||
1547 | |||
1548 | /* Link is now in state WORKING_WORKING */ | ||
1549 | if (unlikely(seq_no != mod(l_ptr->next_in_no))) { | ||
1747 | link_handle_out_of_seq_msg(l_ptr, buf); | 1550 | link_handle_out_of_seq_msg(l_ptr, buf); |
1748 | head = link_insert_deferred_queue(l_ptr, head); | 1551 | head = link_insert_deferred_queue(l_ptr, head); |
1749 | tipc_node_unlock(n_ptr); | 1552 | tipc_node_unlock(n_ptr); |
1750 | continue; | 1553 | continue; |
1751 | } | 1554 | } |
1752 | 1555 | l_ptr->next_in_no++; | |
1753 | /* Link is not in state WORKING_WORKING */ | 1556 | if (unlikely(l_ptr->oldest_deferred_in)) |
1754 | if (msg_user(msg) == LINK_PROTOCOL) { | ||
1755 | link_recv_proto_msg(l_ptr, buf); | ||
1756 | head = link_insert_deferred_queue(l_ptr, head); | 1557 | head = link_insert_deferred_queue(l_ptr, head); |
1558 | deliver: | ||
1559 | if (likely(msg_isdata(msg))) { | ||
1757 | tipc_node_unlock(n_ptr); | 1560 | tipc_node_unlock(n_ptr); |
1561 | tipc_port_recv_msg(buf); | ||
1758 | continue; | 1562 | continue; |
1759 | } | 1563 | } |
1760 | 1564 | switch (msg_user(msg)) { | |
1761 | /* Traffic message. Conditionally activate link */ | 1565 | int ret; |
1762 | link_state_event(l_ptr, TRAFFIC_MSG_EVT); | 1566 | case MSG_BUNDLER: |
1763 | 1567 | l_ptr->stats.recv_bundles++; | |
1764 | if (link_working_working(l_ptr)) { | 1568 | l_ptr->stats.recv_bundled += msg_msgcnt(msg); |
1765 | /* Re-insert buffer in front of queue */ | 1569 | tipc_node_unlock(n_ptr); |
1766 | buf->next = head; | 1570 | tipc_link_recv_bundle(buf); |
1767 | head = buf; | 1571 | continue; |
1572 | case NAME_DISTRIBUTOR: | ||
1573 | n_ptr->bclink.recv_permitted = true; | ||
1574 | tipc_node_unlock(n_ptr); | ||
1575 | tipc_named_recv(buf); | ||
1576 | continue; | ||
1577 | case BCAST_PROTOCOL: | ||
1578 | tipc_link_recv_sync(n_ptr, buf); | ||
1579 | tipc_node_unlock(n_ptr); | ||
1580 | continue; | ||
1581 | case CONN_MANAGER: | ||
1582 | tipc_node_unlock(n_ptr); | ||
1583 | tipc_port_recv_proto_msg(buf); | ||
1584 | continue; | ||
1585 | case MSG_FRAGMENTER: | ||
1586 | l_ptr->stats.recv_fragments++; | ||
1587 | ret = tipc_link_recv_fragment(&l_ptr->reasm_head, | ||
1588 | &l_ptr->reasm_tail, | ||
1589 | &buf); | ||
1590 | if (ret == LINK_REASM_COMPLETE) { | ||
1591 | l_ptr->stats.recv_fragmented++; | ||
1592 | msg = buf_msg(buf); | ||
1593 | goto deliver; | ||
1594 | } | ||
1595 | if (ret == LINK_REASM_ERROR) | ||
1596 | tipc_link_reset(l_ptr); | ||
1768 | tipc_node_unlock(n_ptr); | 1597 | tipc_node_unlock(n_ptr); |
1769 | continue; | 1598 | continue; |
1599 | case CHANGEOVER_PROTOCOL: | ||
1600 | type = msg_type(msg); | ||
1601 | if (tipc_link_tunnel_rcv(&l_ptr, &buf)) { | ||
1602 | msg = buf_msg(buf); | ||
1603 | seq_no = msg_seqno(msg); | ||
1604 | if (type == ORIGINAL_MSG) | ||
1605 | goto deliver; | ||
1606 | goto protocol_check; | ||
1607 | } | ||
1608 | break; | ||
1609 | default: | ||
1610 | kfree_skb(buf); | ||
1611 | buf = NULL; | ||
1612 | break; | ||
1770 | } | 1613 | } |
1771 | tipc_node_unlock(n_ptr); | 1614 | tipc_node_unlock(n_ptr); |
1772 | cont: | 1615 | tipc_net_route_msg(buf); |
1616 | continue; | ||
1617 | unlock_discard: | ||
1618 | |||
1619 | tipc_node_unlock(n_ptr); | ||
1620 | discard: | ||
1773 | kfree_skb(buf); | 1621 | kfree_skb(buf); |
1774 | } | 1622 | } |
1775 | read_unlock_bh(&tipc_net_lock); | 1623 | read_unlock_bh(&tipc_net_lock); |
@@ -1879,7 +1727,8 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, | |||
1879 | l_ptr->proto_msg_queue = NULL; | 1727 | l_ptr->proto_msg_queue = NULL; |
1880 | } | 1728 | } |
1881 | 1729 | ||
1882 | if (link_blocked(l_ptr)) | 1730 | /* Don't send protocol message during link changeover */ |
1731 | if (l_ptr->exp_msg_count) | ||
1883 | return; | 1732 | return; |
1884 | 1733 | ||
1885 | /* Abort non-RESET send if communication with node is prohibited */ | 1734 | /* Abort non-RESET send if communication with node is prohibited */ |
@@ -1954,12 +1803,6 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, | |||
1954 | skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); | 1803 | skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); |
1955 | buf->priority = TC_PRIO_CONTROL; | 1804 | buf->priority = TC_PRIO_CONTROL; |
1956 | 1805 | ||
1957 | /* Defer message if bearer is already blocked */ | ||
1958 | if (tipc_bearer_blocked(l_ptr->b_ptr)) { | ||
1959 | l_ptr->proto_msg_queue = buf; | ||
1960 | return; | ||
1961 | } | ||
1962 | |||
1963 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); | 1806 | tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr); |
1964 | l_ptr->unacked_window = 0; | 1807 | l_ptr->unacked_window = 0; |
1965 | kfree_skb(buf); | 1808 | kfree_skb(buf); |
@@ -1978,7 +1821,8 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
1978 | u32 msg_tol; | 1821 | u32 msg_tol; |
1979 | struct tipc_msg *msg = buf_msg(buf); | 1822 | struct tipc_msg *msg = buf_msg(buf); |
1980 | 1823 | ||
1981 | if (link_blocked(l_ptr)) | 1824 | /* Discard protocol message during link changeover */ |
1825 | if (l_ptr->exp_msg_count) | ||
1982 | goto exit; | 1826 | goto exit; |
1983 | 1827 | ||
1984 | /* record unnumbered packet arrival (force mismatch on next timeout) */ | 1828 | /* record unnumbered packet arrival (force mismatch on next timeout) */ |
@@ -1988,8 +1832,6 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
1988 | if (tipc_own_addr > msg_prevnode(msg)) | 1832 | if (tipc_own_addr > msg_prevnode(msg)) |
1989 | l_ptr->b_ptr->net_plane = msg_net_plane(msg); | 1833 | l_ptr->b_ptr->net_plane = msg_net_plane(msg); |
1990 | 1834 | ||
1991 | l_ptr->owner->permit_changeover = msg_redundant_link(msg); | ||
1992 | |||
1993 | switch (msg_type(msg)) { | 1835 | switch (msg_type(msg)) { |
1994 | 1836 | ||
1995 | case RESET_MSG: | 1837 | case RESET_MSG: |
@@ -2105,13 +1947,13 @@ exit: | |||
2105 | } | 1947 | } |
2106 | 1948 | ||
2107 | 1949 | ||
2108 | /* | 1950 | /* tipc_link_tunnel_xmit(): Tunnel one packet via a link belonging to |
2109 | * tipc_link_tunnel(): Send one message via a link belonging to | 1951 | * a different bearer. Owner node is locked. |
2110 | * another bearer. Owner node is locked. | ||
2111 | */ | 1952 | */ |
2112 | static void tipc_link_tunnel(struct tipc_link *l_ptr, | 1953 | static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr, |
2113 | struct tipc_msg *tunnel_hdr, struct tipc_msg *msg, | 1954 | struct tipc_msg *tunnel_hdr, |
2114 | u32 selector) | 1955 | struct tipc_msg *msg, |
1956 | u32 selector) | ||
2115 | { | 1957 | { |
2116 | struct tipc_link *tunnel; | 1958 | struct tipc_link *tunnel; |
2117 | struct sk_buff *buf; | 1959 | struct sk_buff *buf; |
@@ -2134,12 +1976,13 @@ static void tipc_link_tunnel(struct tipc_link *l_ptr, | |||
2134 | } | 1976 | } |
2135 | 1977 | ||
2136 | 1978 | ||
2137 | 1979 | /* tipc_link_failover_send_queue(): A link has gone down, but a second | |
2138 | /* | 1980 | * link is still active. We can do failover. Tunnel the failing link's |
2139 | * changeover(): Send whole message queue via the remaining link | 1981 | * whole send queue via the remaining link. This way, we don't lose |
2140 | * Owner node is locked. | 1982 | * any packets, and sequence order is preserved for subsequent traffic |
1983 | * sent over the remaining link. Owner node is locked. | ||
2141 | */ | 1984 | */ |
2142 | void tipc_link_changeover(struct tipc_link *l_ptr) | 1985 | void tipc_link_failover_send_queue(struct tipc_link *l_ptr) |
2143 | { | 1986 | { |
2144 | u32 msgcount = l_ptr->out_queue_size; | 1987 | u32 msgcount = l_ptr->out_queue_size; |
2145 | struct sk_buff *crs = l_ptr->first_out; | 1988 | struct sk_buff *crs = l_ptr->first_out; |
@@ -2150,11 +1993,6 @@ void tipc_link_changeover(struct tipc_link *l_ptr) | |||
2150 | if (!tunnel) | 1993 | if (!tunnel) |
2151 | return; | 1994 | return; |
2152 | 1995 | ||
2153 | if (!l_ptr->owner->permit_changeover) { | ||
2154 | pr_warn("%speer did not permit changeover\n", link_co_err); | ||
2155 | return; | ||
2156 | } | ||
2157 | |||
2158 | tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, | 1996 | tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, |
2159 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); | 1997 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); |
2160 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); | 1998 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); |
@@ -2188,20 +2026,30 @@ void tipc_link_changeover(struct tipc_link *l_ptr) | |||
2188 | msgcount = msg_msgcnt(msg); | 2026 | msgcount = msg_msgcnt(msg); |
2189 | while (msgcount--) { | 2027 | while (msgcount--) { |
2190 | msg_set_seqno(m, msg_seqno(msg)); | 2028 | msg_set_seqno(m, msg_seqno(msg)); |
2191 | tipc_link_tunnel(l_ptr, &tunnel_hdr, m, | 2029 | tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, m, |
2192 | msg_link_selector(m)); | 2030 | msg_link_selector(m)); |
2193 | pos += align(msg_size(m)); | 2031 | pos += align(msg_size(m)); |
2194 | m = (struct tipc_msg *)pos; | 2032 | m = (struct tipc_msg *)pos; |
2195 | } | 2033 | } |
2196 | } else { | 2034 | } else { |
2197 | tipc_link_tunnel(l_ptr, &tunnel_hdr, msg, | 2035 | tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, msg, |
2198 | msg_link_selector(msg)); | 2036 | msg_link_selector(msg)); |
2199 | } | 2037 | } |
2200 | crs = crs->next; | 2038 | crs = crs->next; |
2201 | } | 2039 | } |
2202 | } | 2040 | } |
2203 | 2041 | ||
2204 | void tipc_link_send_duplicate(struct tipc_link *l_ptr, struct tipc_link *tunnel) | 2042 | /* tipc_link_dup_send_queue(): A second link has become active. Tunnel a |
2043 | * duplicate of the first link's send queue via the new link. This way, we | ||
2044 | * are guaranteed that currently queued packets from a socket are delivered | ||
2045 | * before future traffic from the same socket, even if this is using the | ||
2046 | * new link. The last arriving copy of each duplicate packet is dropped at | ||
2047 | * the receiving end by the regular protocol check, so packet cardinality | ||
2048 | * and sequence order is preserved per sender/receiver socket pair. | ||
2049 | * Owner node is locked. | ||
2050 | */ | ||
2051 | void tipc_link_dup_send_queue(struct tipc_link *l_ptr, | ||
2052 | struct tipc_link *tunnel) | ||
2205 | { | 2053 | { |
2206 | struct sk_buff *iter; | 2054 | struct sk_buff *iter; |
2207 | struct tipc_msg tunnel_hdr; | 2055 | struct tipc_msg tunnel_hdr; |
@@ -2257,12 +2105,14 @@ static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos) | |||
2257 | return eb; | 2105 | return eb; |
2258 | } | 2106 | } |
2259 | 2107 | ||
2260 | /* | 2108 | /* tipc_link_tunnel_rcv(): Receive a tunneled packet, sent |
2261 | * link_recv_changeover_msg(): Receive tunneled packet sent | 2109 | * via other link as result of a failover (ORIGINAL_MSG) or |
2262 | * via other link. Node is locked. Return extracted buffer. | 2110 | * a new active link (DUPLICATE_MSG). Failover packets are |
2111 | * returned to the active link for delivery upwards. | ||
2112 | * Owner node is locked. | ||
2263 | */ | 2113 | */ |
2264 | static int link_recv_changeover_msg(struct tipc_link **l_ptr, | 2114 | static int tipc_link_tunnel_rcv(struct tipc_link **l_ptr, |
2265 | struct sk_buff **buf) | 2115 | struct sk_buff **buf) |
2266 | { | 2116 | { |
2267 | struct sk_buff *tunnel_buf = *buf; | 2117 | struct sk_buff *tunnel_buf = *buf; |
2268 | struct tipc_link *dest_link; | 2118 | struct tipc_link *dest_link; |
@@ -2399,11 +2249,7 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
2399 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | 2249 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); |
2400 | if (fragm == NULL) { | 2250 | if (fragm == NULL) { |
2401 | kfree_skb(buf); | 2251 | kfree_skb(buf); |
2402 | while (buf_chain) { | 2252 | kfree_skb_list(buf_chain); |
2403 | buf = buf_chain; | ||
2404 | buf_chain = buf_chain->next; | ||
2405 | kfree_skb(buf); | ||
2406 | } | ||
2407 | return -ENOMEM; | 2253 | return -ENOMEM; |
2408 | } | 2254 | } |
2409 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | 2255 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); |
@@ -2432,114 +2278,48 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
2432 | } | 2278 | } |
2433 | 2279 | ||
2434 | /* | 2280 | /* |
2435 | * A pending message being re-assembled must store certain values | ||
2436 | * to handle subsequent fragments correctly. The following functions | ||
2437 | * help storing these values in unused, available fields in the | ||
2438 | * pending message. This makes dynamic memory allocation unnecessary. | ||
2439 | */ | ||
2440 | static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno) | ||
2441 | { | ||
2442 | msg_set_seqno(buf_msg(buf), seqno); | ||
2443 | } | ||
2444 | |||
2445 | static u32 get_fragm_size(struct sk_buff *buf) | ||
2446 | { | ||
2447 | return msg_ack(buf_msg(buf)); | ||
2448 | } | ||
2449 | |||
2450 | static void set_fragm_size(struct sk_buff *buf, u32 sz) | ||
2451 | { | ||
2452 | msg_set_ack(buf_msg(buf), sz); | ||
2453 | } | ||
2454 | |||
2455 | static u32 get_expected_frags(struct sk_buff *buf) | ||
2456 | { | ||
2457 | return msg_bcast_ack(buf_msg(buf)); | ||
2458 | } | ||
2459 | |||
2460 | static void set_expected_frags(struct sk_buff *buf, u32 exp) | ||
2461 | { | ||
2462 | msg_set_bcast_ack(buf_msg(buf), exp); | ||
2463 | } | ||
2464 | |||
2465 | /* | ||
2466 | * tipc_link_recv_fragment(): Called with node lock on. Returns | 2281 | * tipc_link_recv_fragment(): Called with node lock on. Returns |
2467 | * the reassembled buffer if message is complete. | 2282 | * the reassembled buffer if message is complete. |
2468 | */ | 2283 | */ |
2469 | int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | 2284 | int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail, |
2470 | struct tipc_msg **m) | 2285 | struct sk_buff **fbuf) |
2471 | { | 2286 | { |
2472 | struct sk_buff *prev = NULL; | 2287 | struct sk_buff *frag = *fbuf; |
2473 | struct sk_buff *fbuf = *fb; | 2288 | struct tipc_msg *msg = buf_msg(frag); |
2474 | struct tipc_msg *fragm = buf_msg(fbuf); | 2289 | u32 fragid = msg_type(msg); |
2475 | struct sk_buff *pbuf = *pending; | 2290 | bool headstolen; |
2476 | u32 long_msg_seq_no = msg_long_msgno(fragm); | 2291 | int delta; |
2477 | 2292 | ||
2478 | *fb = NULL; | 2293 | skb_pull(frag, msg_hdr_sz(msg)); |
2479 | 2294 | if (fragid == FIRST_FRAGMENT) { | |
2480 | /* Is there an incomplete message waiting for this fragment? */ | 2295 | if (*head || skb_unclone(frag, GFP_ATOMIC)) |
2481 | while (pbuf && ((buf_seqno(pbuf) != long_msg_seq_no) || | 2296 | goto out_free; |
2482 | (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) { | 2297 | *head = frag; |
2483 | prev = pbuf; | 2298 | skb_frag_list_init(*head); |
2484 | pbuf = pbuf->next; | ||
2485 | } | ||
2486 | |||
2487 | if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) { | ||
2488 | struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm); | ||
2489 | u32 msg_sz = msg_size(imsg); | ||
2490 | u32 fragm_sz = msg_data_sz(fragm); | ||
2491 | u32 exp_fragm_cnt; | ||
2492 | u32 max = TIPC_MAX_USER_MSG_SIZE + NAMED_H_SIZE; | ||
2493 | |||
2494 | if (msg_type(imsg) == TIPC_MCAST_MSG) | ||
2495 | max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE; | ||
2496 | if (fragm_sz == 0 || msg_size(imsg) > max) { | ||
2497 | kfree_skb(fbuf); | ||
2498 | return 0; | ||
2499 | } | ||
2500 | exp_fragm_cnt = msg_sz / fragm_sz + !!(msg_sz % fragm_sz); | ||
2501 | pbuf = tipc_buf_acquire(msg_size(imsg)); | ||
2502 | if (pbuf != NULL) { | ||
2503 | pbuf->next = *pending; | ||
2504 | *pending = pbuf; | ||
2505 | skb_copy_to_linear_data(pbuf, imsg, | ||
2506 | msg_data_sz(fragm)); | ||
2507 | /* Prepare buffer for subsequent fragments. */ | ||
2508 | set_long_msg_seqno(pbuf, long_msg_seq_no); | ||
2509 | set_fragm_size(pbuf, fragm_sz); | ||
2510 | set_expected_frags(pbuf, exp_fragm_cnt - 1); | ||
2511 | } else { | ||
2512 | pr_debug("Link unable to reassemble fragmented message\n"); | ||
2513 | kfree_skb(fbuf); | ||
2514 | return -1; | ||
2515 | } | ||
2516 | kfree_skb(fbuf); | ||
2517 | return 0; | ||
2518 | } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) { | ||
2519 | u32 dsz = msg_data_sz(fragm); | ||
2520 | u32 fsz = get_fragm_size(pbuf); | ||
2521 | u32 crs = ((msg_fragm_no(fragm) - 1) * fsz); | ||
2522 | u32 exp_frags = get_expected_frags(pbuf) - 1; | ||
2523 | skb_copy_to_linear_data_offset(pbuf, crs, | ||
2524 | msg_data(fragm), dsz); | ||
2525 | kfree_skb(fbuf); | ||
2526 | |||
2527 | /* Is message complete? */ | ||
2528 | if (exp_frags == 0) { | ||
2529 | if (prev) | ||
2530 | prev->next = pbuf->next; | ||
2531 | else | ||
2532 | *pending = pbuf->next; | ||
2533 | msg_reset_reroute_cnt(buf_msg(pbuf)); | ||
2534 | *fb = pbuf; | ||
2535 | *m = buf_msg(pbuf); | ||
2536 | return 1; | ||
2537 | } | ||
2538 | set_expected_frags(pbuf, exp_frags); | ||
2539 | return 0; | 2299 | return 0; |
2300 | } else if (*head && | ||
2301 | skb_try_coalesce(*head, frag, &headstolen, &delta)) { | ||
2302 | kfree_skb_partial(frag, headstolen); | ||
2303 | } else { | ||
2304 | if (!*head) | ||
2305 | goto out_free; | ||
2306 | if (!skb_has_frag_list(*head)) | ||
2307 | skb_shinfo(*head)->frag_list = frag; | ||
2308 | else | ||
2309 | (*tail)->next = frag; | ||
2310 | *tail = frag; | ||
2311 | (*head)->truesize += frag->truesize; | ||
2312 | } | ||
2313 | if (fragid == LAST_FRAGMENT) { | ||
2314 | *fbuf = *head; | ||
2315 | *tail = *head = NULL; | ||
2316 | return LINK_REASM_COMPLETE; | ||
2540 | } | 2317 | } |
2541 | kfree_skb(fbuf); | ||
2542 | return 0; | 2318 | return 0; |
2319 | out_free: | ||
2320 | pr_warn_ratelimited("Link unable to reassemble fragmented message\n"); | ||
2321 | kfree_skb(*fbuf); | ||
2322 | return LINK_REASM_ERROR; | ||
2543 | } | 2323 | } |
2544 | 2324 | ||
2545 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) | 2325 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) |
@@ -2585,25 +2365,21 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window) | |||
2585 | static struct tipc_link *link_find_link(const char *name, | 2365 | static struct tipc_link *link_find_link(const char *name, |
2586 | struct tipc_node **node) | 2366 | struct tipc_node **node) |
2587 | { | 2367 | { |
2588 | struct tipc_link_name link_name_parts; | ||
2589 | struct tipc_bearer *b_ptr; | ||
2590 | struct tipc_link *l_ptr; | 2368 | struct tipc_link *l_ptr; |
2369 | struct tipc_node *n_ptr; | ||
2370 | int i; | ||
2591 | 2371 | ||
2592 | if (!link_name_validate(name, &link_name_parts)) | 2372 | list_for_each_entry(n_ptr, &tipc_node_list, list) { |
2593 | return NULL; | 2373 | for (i = 0; i < MAX_BEARERS; i++) { |
2594 | 2374 | l_ptr = n_ptr->links[i]; | |
2595 | b_ptr = tipc_bearer_find_interface(link_name_parts.if_local); | 2375 | if (l_ptr && !strcmp(l_ptr->name, name)) |
2596 | if (!b_ptr) | 2376 | goto found; |
2597 | return NULL; | 2377 | } |
2598 | 2378 | } | |
2599 | *node = tipc_node_find(link_name_parts.addr_peer); | 2379 | l_ptr = NULL; |
2600 | if (!*node) | 2380 | n_ptr = NULL; |
2601 | return NULL; | 2381 | found: |
2602 | 2382 | *node = n_ptr; | |
2603 | l_ptr = (*node)->links[b_ptr->identity]; | ||
2604 | if (!l_ptr || strcmp(l_ptr->name, name)) | ||
2605 | return NULL; | ||
2606 | |||
2607 | return l_ptr; | 2383 | return l_ptr; |
2608 | } | 2384 | } |
2609 | 2385 | ||
@@ -2646,6 +2422,7 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2646 | struct tipc_link *l_ptr; | 2422 | struct tipc_link *l_ptr; |
2647 | struct tipc_bearer *b_ptr; | 2423 | struct tipc_bearer *b_ptr; |
2648 | struct tipc_media *m_ptr; | 2424 | struct tipc_media *m_ptr; |
2425 | int res = 0; | ||
2649 | 2426 | ||
2650 | l_ptr = link_find_link(name, &node); | 2427 | l_ptr = link_find_link(name, &node); |
2651 | if (l_ptr) { | 2428 | if (l_ptr) { |
@@ -2668,9 +2445,12 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2668 | case TIPC_CMD_SET_LINK_WINDOW: | 2445 | case TIPC_CMD_SET_LINK_WINDOW: |
2669 | tipc_link_set_queue_limits(l_ptr, new_value); | 2446 | tipc_link_set_queue_limits(l_ptr, new_value); |
2670 | break; | 2447 | break; |
2448 | default: | ||
2449 | res = -EINVAL; | ||
2450 | break; | ||
2671 | } | 2451 | } |
2672 | tipc_node_unlock(node); | 2452 | tipc_node_unlock(node); |
2673 | return 0; | 2453 | return res; |
2674 | } | 2454 | } |
2675 | 2455 | ||
2676 | b_ptr = tipc_bearer_find(name); | 2456 | b_ptr = tipc_bearer_find(name); |
@@ -2678,15 +2458,18 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2678 | switch (cmd) { | 2458 | switch (cmd) { |
2679 | case TIPC_CMD_SET_LINK_TOL: | 2459 | case TIPC_CMD_SET_LINK_TOL: |
2680 | b_ptr->tolerance = new_value; | 2460 | b_ptr->tolerance = new_value; |
2681 | return 0; | 2461 | break; |
2682 | case TIPC_CMD_SET_LINK_PRI: | 2462 | case TIPC_CMD_SET_LINK_PRI: |
2683 | b_ptr->priority = new_value; | 2463 | b_ptr->priority = new_value; |
2684 | return 0; | 2464 | break; |
2685 | case TIPC_CMD_SET_LINK_WINDOW: | 2465 | case TIPC_CMD_SET_LINK_WINDOW: |
2686 | b_ptr->window = new_value; | 2466 | b_ptr->window = new_value; |
2687 | return 0; | 2467 | break; |
2468 | default: | ||
2469 | res = -EINVAL; | ||
2470 | break; | ||
2688 | } | 2471 | } |
2689 | return -EINVAL; | 2472 | return res; |
2690 | } | 2473 | } |
2691 | 2474 | ||
2692 | m_ptr = tipc_media_find(name); | 2475 | m_ptr = tipc_media_find(name); |
@@ -2695,15 +2478,18 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) | |||
2695 | switch (cmd) { | 2478 | switch (cmd) { |
2696 | case TIPC_CMD_SET_LINK_TOL: | 2479 | case TIPC_CMD_SET_LINK_TOL: |
2697 | m_ptr->tolerance = new_value; | 2480 | m_ptr->tolerance = new_value; |
2698 | return 0; | 2481 | break; |
2699 | case TIPC_CMD_SET_LINK_PRI: | 2482 | case TIPC_CMD_SET_LINK_PRI: |
2700 | m_ptr->priority = new_value; | 2483 | m_ptr->priority = new_value; |
2701 | return 0; | 2484 | break; |
2702 | case TIPC_CMD_SET_LINK_WINDOW: | 2485 | case TIPC_CMD_SET_LINK_WINDOW: |
2703 | m_ptr->window = new_value; | 2486 | m_ptr->window = new_value; |
2704 | return 0; | 2487 | break; |
2488 | default: | ||
2489 | res = -EINVAL; | ||
2490 | break; | ||
2705 | } | 2491 | } |
2706 | return -EINVAL; | 2492 | return res; |
2707 | } | 2493 | } |
2708 | 2494 | ||
2709 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, | 2495 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, |
diff --git a/net/tipc/link.h b/net/tipc/link.h index c048ed1cbd76..3b6aa65b608c 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
@@ -41,6 +41,12 @@ | |||
41 | #include "node.h" | 41 | #include "node.h" |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * Link reassembly status codes | ||
45 | */ | ||
46 | #define LINK_REASM_ERROR -1 | ||
47 | #define LINK_REASM_COMPLETE 1 | ||
48 | |||
49 | /* | ||
44 | * Out-of-range value for link sequence numbers | 50 | * Out-of-range value for link sequence numbers |
45 | */ | 51 | */ |
46 | #define INVALID_LINK_SEQ 0x10000 | 52 | #define INVALID_LINK_SEQ 0x10000 |
@@ -106,7 +112,6 @@ struct tipc_stats { | |||
106 | * @continuity_interval: link continuity testing interval [in ms] | 112 | * @continuity_interval: link continuity testing interval [in ms] |
107 | * @abort_limit: # of unacknowledged continuity probes needed to reset link | 113 | * @abort_limit: # of unacknowledged continuity probes needed to reset link |
108 | * @state: current state of link FSM | 114 | * @state: current state of link FSM |
109 | * @blocked: indicates if link has been administratively blocked | ||
110 | * @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 |
111 | * @proto_msg: template for control messages generated by link | 116 | * @proto_msg: template for control messages generated by link |
112 | * @pmsg: convenience pointer to "proto_msg" field | 117 | * @pmsg: convenience pointer to "proto_msg" field |
@@ -134,7 +139,8 @@ struct tipc_stats { | |||
134 | * @next_out: ptr to first unsent outbound message in queue | 139 | * @next_out: ptr to first unsent outbound message in queue |
135 | * @waiting_ports: linked list of ports waiting for link congestion to abate | 140 | * @waiting_ports: linked list of ports waiting for link congestion to abate |
136 | * @long_msg_seq_no: next identifier to use for outbound fragmented messages | 141 | * @long_msg_seq_no: next identifier to use for outbound fragmented messages |
137 | * @defragm_buf: list of partially reassembled inbound message fragments | 142 | * @reasm_head: list head of partially reassembled inbound message fragments |
143 | * @reasm_tail: last fragment received | ||
138 | * @stats: collects statistics regarding link activity | 144 | * @stats: collects statistics regarding link activity |
139 | */ | 145 | */ |
140 | struct tipc_link { | 146 | struct tipc_link { |
@@ -155,7 +161,6 @@ struct tipc_link { | |||
155 | u32 continuity_interval; | 161 | u32 continuity_interval; |
156 | u32 abort_limit; | 162 | u32 abort_limit; |
157 | int state; | 163 | int state; |
158 | int blocked; | ||
159 | u32 fsm_msg_cnt; | 164 | u32 fsm_msg_cnt; |
160 | struct { | 165 | struct { |
161 | unchar hdr[INT_H_SIZE]; | 166 | unchar hdr[INT_H_SIZE]; |
@@ -196,9 +201,10 @@ struct tipc_link { | |||
196 | struct sk_buff *next_out; | 201 | struct sk_buff *next_out; |
197 | struct list_head waiting_ports; | 202 | struct list_head waiting_ports; |
198 | 203 | ||
199 | /* Fragmentation/defragmentation */ | 204 | /* Fragmentation/reassembly */ |
200 | u32 long_msg_seq_no; | 205 | u32 long_msg_seq_no; |
201 | struct sk_buff *defragm_buf; | 206 | struct sk_buff *reasm_head; |
207 | struct sk_buff *reasm_tail; | ||
202 | 208 | ||
203 | /* Statistics */ | 209 | /* Statistics */ |
204 | struct tipc_stats stats; | 210 | struct tipc_stats stats; |
@@ -210,16 +216,20 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
210 | struct tipc_bearer *b_ptr, | 216 | struct tipc_bearer *b_ptr, |
211 | const struct tipc_media_addr *media_addr); | 217 | const struct tipc_media_addr *media_addr); |
212 | void tipc_link_delete(struct tipc_link *l_ptr); | 218 | void tipc_link_delete(struct tipc_link *l_ptr); |
213 | void tipc_link_changeover(struct tipc_link *l_ptr); | 219 | void tipc_link_failover_send_queue(struct tipc_link *l_ptr); |
214 | 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); | ||
215 | void tipc_link_reset_fragments(struct tipc_link *l_ptr); | 222 | void tipc_link_reset_fragments(struct tipc_link *l_ptr); |
216 | int tipc_link_is_up(struct tipc_link *l_ptr); | 223 | int tipc_link_is_up(struct tipc_link *l_ptr); |
217 | int tipc_link_is_active(struct tipc_link *l_ptr); | 224 | int tipc_link_is_active(struct tipc_link *l_ptr); |
218 | u32 tipc_link_push_packet(struct tipc_link *l_ptr); | 225 | void tipc_link_purge_queues(struct tipc_link *l_ptr); |
219 | void tipc_link_stop(struct tipc_link *l_ptr); | 226 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, |
220 | struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd); | 227 | int req_tlv_space, |
221 | struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space); | 228 | u16 cmd); |
222 | 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); | ||
223 | void tipc_link_reset(struct tipc_link *l_ptr); | 233 | void tipc_link_reset(struct tipc_link *l_ptr); |
224 | 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); |
225 | 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); |
@@ -227,13 +237,11 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf); | |||
227 | u32 tipc_link_get_max_pkt(u32 dest, u32 selector); | 237 | u32 tipc_link_get_max_pkt(u32 dest, u32 selector); |
228 | int tipc_link_send_sections_fast(struct tipc_port *sender, | 238 | int tipc_link_send_sections_fast(struct tipc_port *sender, |
229 | struct iovec const *msg_sect, | 239 | struct iovec const *msg_sect, |
230 | const u32 num_sect, | 240 | unsigned int len, u32 destnode); |
231 | unsigned int total_len, | ||
232 | u32 destnode); | ||
233 | void tipc_link_recv_bundle(struct sk_buff *buf); | 241 | void tipc_link_recv_bundle(struct sk_buff *buf); |
234 | int tipc_link_recv_fragment(struct sk_buff **pending, | 242 | int tipc_link_recv_fragment(struct sk_buff **reasm_head, |
235 | struct sk_buff **fb, | 243 | struct sk_buff **reasm_tail, |
236 | struct tipc_msg **msg); | 244 | struct sk_buff **fbuf); |
237 | void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, int prob, | 245 | void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, int prob, |
238 | u32 gap, u32 tolerance, u32 priority, | 246 | u32 gap, u32 tolerance, u32 priority, |
239 | u32 acked_mtu); | 247 | u32 acked_mtu); |
@@ -306,11 +314,6 @@ static inline int link_reset_reset(struct tipc_link *l_ptr) | |||
306 | return l_ptr->state == RESET_RESET; | 314 | return l_ptr->state == RESET_RESET; |
307 | } | 315 | } |
308 | 316 | ||
309 | static inline int link_blocked(struct tipc_link *l_ptr) | ||
310 | { | ||
311 | return l_ptr->exp_msg_count || l_ptr->blocked; | ||
312 | } | ||
313 | |||
314 | static inline int link_congested(struct tipc_link *l_ptr) | 317 | static inline int link_congested(struct tipc_link *l_ptr) |
315 | { | 318 | { |
316 | 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/msg.c b/net/tipc/msg.c index ced60e2fc4f7..e525f8ce1dee 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
@@ -73,13 +73,13 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | |||
73 | * Returns message data size or errno | 73 | * Returns message data size or errno |
74 | */ | 74 | */ |
75 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | 75 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, |
76 | u32 num_sect, unsigned int total_len, int max_size, | 76 | unsigned int len, int max_size, struct sk_buff **buf) |
77 | struct sk_buff **buf) | ||
78 | { | 77 | { |
79 | int dsz, sz, hsz, pos, res, cnt; | 78 | int dsz, sz, hsz; |
79 | unsigned char *to; | ||
80 | 80 | ||
81 | dsz = total_len; | 81 | dsz = len; |
82 | pos = hsz = msg_hdr_sz(hdr); | 82 | hsz = msg_hdr_sz(hdr); |
83 | sz = hsz + dsz; | 83 | sz = hsz + dsz; |
84 | msg_set_size(hdr, sz); | 84 | msg_set_size(hdr, sz); |
85 | if (unlikely(sz > max_size)) { | 85 | if (unlikely(sz > max_size)) { |
@@ -91,16 +91,11 @@ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | |||
91 | if (!(*buf)) | 91 | if (!(*buf)) |
92 | return -ENOMEM; | 92 | return -ENOMEM; |
93 | skb_copy_to_linear_data(*buf, hdr, hsz); | 93 | skb_copy_to_linear_data(*buf, hdr, hsz); |
94 | for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) { | 94 | to = (*buf)->data + hsz; |
95 | skb_copy_to_linear_data_offset(*buf, pos, | 95 | if (len && memcpy_fromiovecend(to, msg_sect, 0, dsz)) { |
96 | msg_sect[cnt].iov_base, | 96 | kfree_skb(*buf); |
97 | msg_sect[cnt].iov_len); | 97 | *buf = NULL; |
98 | pos += msg_sect[cnt].iov_len; | 98 | return -EFAULT; |
99 | } | 99 | } |
100 | if (likely(res)) | 100 | return dsz; |
101 | return dsz; | ||
102 | |||
103 | kfree_skb(*buf); | ||
104 | *buf = NULL; | ||
105 | return -EFAULT; | ||
106 | } | 101 | } |
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 5e4ccf5c27df..76d1269b9443 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
@@ -554,12 +554,6 @@ static inline void msg_set_last_bcast(struct tipc_msg *m, u32 n) | |||
554 | msg_set_bits(m, 4, 16, 0xffff, n); | 554 | msg_set_bits(m, 4, 16, 0xffff, n); |
555 | } | 555 | } |
556 | 556 | ||
557 | |||
558 | static inline u32 msg_fragm_no(struct tipc_msg *m) | ||
559 | { | ||
560 | return msg_bits(m, 4, 16, 0xffff); | ||
561 | } | ||
562 | |||
563 | static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n) | 557 | static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n) |
564 | { | 558 | { |
565 | msg_set_bits(m, 4, 16, 0xffff, n); | 559 | msg_set_bits(m, 4, 16, 0xffff, n); |
@@ -576,12 +570,6 @@ static inline void msg_set_next_sent(struct tipc_msg *m, u32 n) | |||
576 | msg_set_bits(m, 4, 0, 0xffff, n); | 570 | msg_set_bits(m, 4, 0, 0xffff, n); |
577 | } | 571 | } |
578 | 572 | ||
579 | |||
580 | static inline u32 msg_long_msgno(struct tipc_msg *m) | ||
581 | { | ||
582 | return msg_bits(m, 4, 0, 0xffff); | ||
583 | } | ||
584 | |||
585 | static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n) | 573 | static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n) |
586 | { | 574 | { |
587 | msg_set_bits(m, 4, 0, 0xffff, n); | 575 | msg_set_bits(m, 4, 0, 0xffff, n); |
@@ -722,6 +710,5 @@ u32 tipc_msg_tot_importance(struct tipc_msg *m); | |||
722 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | 710 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, |
723 | u32 destnode); | 711 | u32 destnode); |
724 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | 712 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, |
725 | u32 num_sect, unsigned int total_len, int max_size, | 713 | unsigned int len, int max_size, struct sk_buff **buf); |
726 | struct sk_buff **buf); | ||
727 | #endif | 714 | #endif |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 09dcd54b04e1..92a1533af4e0 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 | /** |
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 8bcd4985d0fb..9f72a6376362 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c | |||
@@ -76,9 +76,11 @@ static struct genl_family tipc_genl_family = { | |||
76 | .maxattr = 0, | 76 | .maxattr = 0, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static struct genl_ops tipc_genl_ops = { | 79 | static struct genl_ops tipc_genl_ops[] = { |
80 | .cmd = TIPC_GENL_CMD, | 80 | { |
81 | .doit = handle_cmd, | 81 | .cmd = TIPC_GENL_CMD, |
82 | .doit = handle_cmd, | ||
83 | }, | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | static int tipc_genl_family_registered; | 86 | static int tipc_genl_family_registered; |
@@ -87,8 +89,7 @@ int tipc_netlink_start(void) | |||
87 | { | 89 | { |
88 | int res; | 90 | int res; |
89 | 91 | ||
90 | res = genl_register_family_with_ops(&tipc_genl_family, | 92 | res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops); |
91 | &tipc_genl_ops, 1); | ||
92 | if (res) { | 93 | if (res) { |
93 | pr_err("Failed to register netlink interface\n"); | 94 | pr_err("Failed to register netlink interface\n"); |
94 | return res; | 95 | return res; |
diff --git a/net/tipc/node.c b/net/tipc/node.c index 6e6c434872e8..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,16 +286,13 @@ 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.defragm) { | 292 | if (n_ptr->bclink.reasm_head) { |
302 | kfree_skb(n_ptr->bclink.defragm); | 293 | kfree_skb(n_ptr->bclink.reasm_head); |
303 | n_ptr->bclink.defragm = NULL; | 294 | n_ptr->bclink.reasm_head = NULL; |
295 | n_ptr->bclink.reasm_tail = NULL; | ||
304 | } | 296 | } |
305 | 297 | ||
306 | tipc_bclink_remove_node(n_ptr->addr); | 298 | tipc_bclink_remove_node(n_ptr->addr); |
diff --git a/net/tipc/node.h b/net/tipc/node.h index 3c189b35b102..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 |
@@ -74,7 +73,8 @@ | |||
74 | * @deferred_size: number of OOS b'cast messages in deferred queue | 73 | * @deferred_size: number of OOS b'cast messages in deferred queue |
75 | * @deferred_head: oldest OOS b'cast message received from node | 74 | * @deferred_head: oldest OOS b'cast message received from node |
76 | * @deferred_tail: newest OOS b'cast message received from node | 75 | * @deferred_tail: newest OOS b'cast message received from node |
77 | * @defragm: list of partially reassembled b'cast message fragments from node | 76 | * @reasm_head: broadcast reassembly queue head from node |
77 | * @reasm_tail: last broadcast fragment received from node | ||
78 | * @recv_permitted: true if node is allowed to receive b'cast messages | 78 | * @recv_permitted: true if node is allowed to receive b'cast messages |
79 | */ | 79 | */ |
80 | struct tipc_node { | 80 | struct tipc_node { |
@@ -88,7 +88,6 @@ struct tipc_node { | |||
88 | int link_cnt; | 88 | int link_cnt; |
89 | int working_links; | 89 | int working_links; |
90 | int block_setup; | 90 | int block_setup; |
91 | int permit_changeover; | ||
92 | u32 signature; | 91 | u32 signature; |
93 | struct { | 92 | struct { |
94 | u32 acked; | 93 | u32 acked; |
@@ -98,7 +97,8 @@ struct tipc_node { | |||
98 | u32 deferred_size; | 97 | u32 deferred_size; |
99 | struct sk_buff *deferred_head; | 98 | struct sk_buff *deferred_head; |
100 | struct sk_buff *deferred_tail; | 99 | struct sk_buff *deferred_tail; |
101 | struct sk_buff *defragm; | 100 | struct sk_buff *reasm_head; |
101 | struct sk_buff *reasm_tail; | ||
102 | bool recv_permitted; | 102 | bool recv_permitted; |
103 | } bclink; | 103 | } bclink; |
104 | }; | 104 | }; |
@@ -113,7 +113,6 @@ void tipc_node_detach_link(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); | 113 | void tipc_node_link_down(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); | 114 | void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); |
115 | int tipc_node_active_links(struct tipc_node *n_ptr); | 115 | int tipc_node_active_links(struct tipc_node *n_ptr); |
116 | int tipc_node_redundant_links(struct tipc_node *n_ptr); | ||
117 | int tipc_node_is_up(struct tipc_node *n_ptr); | 116 | int tipc_node_is_up(struct tipc_node *n_ptr); |
118 | 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); |
119 | 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 b3ed2fcab4fb..b742b2654525 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
@@ -90,8 +90,7 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) | |||
90 | * tipc_multicast - send a multicast message to local and remote destinations | 90 | * tipc_multicast - send a multicast message to local and remote destinations |
91 | */ | 91 | */ |
92 | int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, | 92 | int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, |
93 | u32 num_sect, struct iovec const *msg_sect, | 93 | struct iovec const *msg_sect, unsigned int len) |
94 | unsigned int total_len) | ||
95 | { | 94 | { |
96 | struct tipc_msg *hdr; | 95 | struct tipc_msg *hdr; |
97 | struct sk_buff *buf; | 96 | struct sk_buff *buf; |
@@ -114,8 +113,7 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, | |||
114 | msg_set_namelower(hdr, seq->lower); | 113 | msg_set_namelower(hdr, seq->lower); |
115 | msg_set_nameupper(hdr, seq->upper); | 114 | msg_set_nameupper(hdr, seq->upper); |
116 | msg_set_hdr_sz(hdr, MCAST_H_SIZE); | 115 | msg_set_hdr_sz(hdr, MCAST_H_SIZE); |
117 | res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, | 116 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); |
118 | &buf); | ||
119 | if (unlikely(!buf)) | 117 | if (unlikely(!buf)) |
120 | return res; | 118 | return res; |
121 | 119 | ||
@@ -253,18 +251,15 @@ struct tipc_port *tipc_createport(struct sock *sk, | |||
253 | return p_ptr; | 251 | return p_ptr; |
254 | } | 252 | } |
255 | 253 | ||
256 | int tipc_deleteport(u32 ref) | 254 | int tipc_deleteport(struct tipc_port *p_ptr) |
257 | { | 255 | { |
258 | struct tipc_port *p_ptr; | ||
259 | struct sk_buff *buf = NULL; | 256 | struct sk_buff *buf = NULL; |
260 | 257 | ||
261 | tipc_withdraw(ref, 0, NULL); | 258 | tipc_withdraw(p_ptr, 0, NULL); |
262 | p_ptr = tipc_port_lock(ref); | ||
263 | if (!p_ptr) | ||
264 | return -EINVAL; | ||
265 | 259 | ||
266 | tipc_ref_discard(ref); | 260 | spin_lock_bh(p_ptr->lock); |
267 | tipc_port_unlock(p_ptr); | 261 | tipc_ref_discard(p_ptr->ref); |
262 | spin_unlock_bh(p_ptr->lock); | ||
268 | 263 | ||
269 | k_cancel_timer(&p_ptr->timer); | 264 | k_cancel_timer(&p_ptr->timer); |
270 | if (p_ptr->connected) { | 265 | if (p_ptr->connected) { |
@@ -436,14 +431,13 @@ exit: | |||
436 | } | 431 | } |
437 | 432 | ||
438 | int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, | 433 | int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, |
439 | struct iovec const *msg_sect, u32 num_sect, | 434 | struct iovec const *msg_sect, unsigned int len, |
440 | unsigned int total_len, int err) | 435 | int err) |
441 | { | 436 | { |
442 | struct sk_buff *buf; | 437 | struct sk_buff *buf; |
443 | int res; | 438 | int res; |
444 | 439 | ||
445 | res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, | 440 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); |
446 | &buf); | ||
447 | if (!buf) | 441 | if (!buf) |
448 | return res; | 442 | return res; |
449 | 443 | ||
@@ -707,47 +701,36 @@ int tipc_set_portimportance(u32 ref, unsigned int imp) | |||
707 | } | 701 | } |
708 | 702 | ||
709 | 703 | ||
710 | int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) | 704 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, |
705 | struct tipc_name_seq const *seq) | ||
711 | { | 706 | { |
712 | struct tipc_port *p_ptr; | ||
713 | struct publication *publ; | 707 | struct publication *publ; |
714 | u32 key; | 708 | u32 key; |
715 | int res = -EINVAL; | ||
716 | 709 | ||
717 | p_ptr = tipc_port_lock(ref); | 710 | if (p_ptr->connected) |
718 | if (!p_ptr) | ||
719 | return -EINVAL; | 711 | return -EINVAL; |
712 | key = p_ptr->ref + p_ptr->pub_count + 1; | ||
713 | if (key == p_ptr->ref) | ||
714 | return -EADDRINUSE; | ||
720 | 715 | ||
721 | if (p_ptr->connected) | ||
722 | goto exit; | ||
723 | key = ref + p_ptr->pub_count + 1; | ||
724 | if (key == ref) { | ||
725 | res = -EADDRINUSE; | ||
726 | goto exit; | ||
727 | } | ||
728 | publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper, | 716 | publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper, |
729 | scope, p_ptr->ref, key); | 717 | scope, p_ptr->ref, key); |
730 | if (publ) { | 718 | if (publ) { |
731 | list_add(&publ->pport_list, &p_ptr->publications); | 719 | list_add(&publ->pport_list, &p_ptr->publications); |
732 | p_ptr->pub_count++; | 720 | p_ptr->pub_count++; |
733 | p_ptr->published = 1; | 721 | p_ptr->published = 1; |
734 | res = 0; | 722 | return 0; |
735 | } | 723 | } |
736 | exit: | 724 | return -EINVAL; |
737 | tipc_port_unlock(p_ptr); | ||
738 | return res; | ||
739 | } | 725 | } |
740 | 726 | ||
741 | int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) | 727 | int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope, |
728 | struct tipc_name_seq const *seq) | ||
742 | { | 729 | { |
743 | struct tipc_port *p_ptr; | ||
744 | struct publication *publ; | 730 | struct publication *publ; |
745 | struct publication *tpubl; | 731 | struct publication *tpubl; |
746 | int res = -EINVAL; | 732 | int res = -EINVAL; |
747 | 733 | ||
748 | p_ptr = tipc_port_lock(ref); | ||
749 | if (!p_ptr) | ||
750 | return -EINVAL; | ||
751 | if (!seq) { | 734 | if (!seq) { |
752 | list_for_each_entry_safe(publ, tpubl, | 735 | list_for_each_entry_safe(publ, tpubl, |
753 | &p_ptr->publications, pport_list) { | 736 | &p_ptr->publications, pport_list) { |
@@ -774,7 +757,6 @@ int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) | |||
774 | } | 757 | } |
775 | if (list_empty(&p_ptr->publications)) | 758 | if (list_empty(&p_ptr->publications)) |
776 | p_ptr->published = 0; | 759 | p_ptr->published = 0; |
777 | tipc_port_unlock(p_ptr); | ||
778 | return res; | 760 | return res; |
779 | } | 761 | } |
780 | 762 | ||
@@ -835,17 +817,14 @@ exit: | |||
835 | */ | 817 | */ |
836 | int __tipc_disconnect(struct tipc_port *tp_ptr) | 818 | int __tipc_disconnect(struct tipc_port *tp_ptr) |
837 | { | 819 | { |
838 | int res; | ||
839 | |||
840 | if (tp_ptr->connected) { | 820 | if (tp_ptr->connected) { |
841 | tp_ptr->connected = 0; | 821 | tp_ptr->connected = 0; |
842 | /* let timer expire on it's own to avoid deadlock! */ | 822 | /* let timer expire on it's own to avoid deadlock! */ |
843 | tipc_nodesub_unsubscribe(&tp_ptr->subscription); | 823 | tipc_nodesub_unsubscribe(&tp_ptr->subscription); |
844 | res = 0; | 824 | return 0; |
845 | } else { | ||
846 | res = -ENOTCONN; | ||
847 | } | 825 | } |
848 | return res; | 826 | |
827 | return -ENOTCONN; | ||
849 | } | 828 | } |
850 | 829 | ||
851 | /* | 830 | /* |
@@ -918,15 +897,14 @@ int tipc_port_recv_msg(struct sk_buff *buf) | |||
918 | * tipc_port_recv_sections(): Concatenate and deliver sectioned | 897 | * tipc_port_recv_sections(): Concatenate and deliver sectioned |
919 | * message for this node. | 898 | * message for this node. |
920 | */ | 899 | */ |
921 | static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_sect, | 900 | static int tipc_port_recv_sections(struct tipc_port *sender, |
922 | struct iovec const *msg_sect, | 901 | struct iovec const *msg_sect, |
923 | unsigned int total_len) | 902 | unsigned int len) |
924 | { | 903 | { |
925 | struct sk_buff *buf; | 904 | struct sk_buff *buf; |
926 | int res; | 905 | int res; |
927 | 906 | ||
928 | res = tipc_msg_build(&sender->phdr, msg_sect, num_sect, total_len, | 907 | res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf); |
929 | MAX_MSG_SIZE, &buf); | ||
930 | if (likely(buf)) | 908 | if (likely(buf)) |
931 | tipc_port_recv_msg(buf); | 909 | tipc_port_recv_msg(buf); |
932 | return res; | 910 | return res; |
@@ -935,8 +913,7 @@ static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_se | |||
935 | /** | 913 | /** |
936 | * tipc_send - send message sections on connection | 914 | * tipc_send - send message sections on connection |
937 | */ | 915 | */ |
938 | int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect, | 916 | int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len) |
939 | unsigned int total_len) | ||
940 | { | 917 | { |
941 | struct tipc_port *p_ptr; | 918 | struct tipc_port *p_ptr; |
942 | u32 destnode; | 919 | u32 destnode; |
@@ -950,11 +927,10 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect, | |||
950 | if (!tipc_port_congested(p_ptr)) { | 927 | if (!tipc_port_congested(p_ptr)) { |
951 | destnode = port_peernode(p_ptr); | 928 | destnode = port_peernode(p_ptr); |
952 | if (likely(!in_own_node(destnode))) | 929 | if (likely(!in_own_node(destnode))) |
953 | res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect, | 930 | res = tipc_link_send_sections_fast(p_ptr, msg_sect, |
954 | total_len, destnode); | 931 | len, destnode); |
955 | else | 932 | else |
956 | res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect, | 933 | res = tipc_port_recv_sections(p_ptr, msg_sect, len); |
957 | total_len); | ||
958 | 934 | ||
959 | if (likely(res != -ELINKCONG)) { | 935 | if (likely(res != -ELINKCONG)) { |
960 | p_ptr->congested = 0; | 936 | p_ptr->congested = 0; |
@@ -965,7 +941,7 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect, | |||
965 | } | 941 | } |
966 | if (port_unreliable(p_ptr)) { | 942 | if (port_unreliable(p_ptr)) { |
967 | p_ptr->congested = 0; | 943 | p_ptr->congested = 0; |
968 | return total_len; | 944 | return len; |
969 | } | 945 | } |
970 | return -ELINKCONG; | 946 | return -ELINKCONG; |
971 | } | 947 | } |
@@ -974,8 +950,7 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect, | |||
974 | * tipc_send2name - send message sections to port name | 950 | * tipc_send2name - send message sections to port name |
975 | */ | 951 | */ |
976 | int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, | 952 | int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, |
977 | unsigned int num_sect, struct iovec const *msg_sect, | 953 | struct iovec const *msg_sect, unsigned int len) |
978 | unsigned int total_len) | ||
979 | { | 954 | { |
980 | struct tipc_port *p_ptr; | 955 | struct tipc_port *p_ptr; |
981 | struct tipc_msg *msg; | 956 | struct tipc_msg *msg; |
@@ -999,36 +974,32 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, | |||
999 | 974 | ||
1000 | if (likely(destport || destnode)) { | 975 | if (likely(destport || destnode)) { |
1001 | if (likely(in_own_node(destnode))) | 976 | if (likely(in_own_node(destnode))) |
1002 | res = tipc_port_recv_sections(p_ptr, num_sect, | 977 | res = tipc_port_recv_sections(p_ptr, msg_sect, len); |
1003 | msg_sect, total_len); | ||
1004 | else if (tipc_own_addr) | 978 | else if (tipc_own_addr) |
1005 | res = tipc_link_send_sections_fast(p_ptr, msg_sect, | 979 | res = tipc_link_send_sections_fast(p_ptr, msg_sect, |
1006 | num_sect, total_len, | 980 | len, destnode); |
1007 | destnode); | ||
1008 | else | 981 | else |
1009 | res = tipc_port_reject_sections(p_ptr, msg, msg_sect, | 982 | res = tipc_port_reject_sections(p_ptr, msg, msg_sect, |
1010 | num_sect, total_len, | 983 | len, TIPC_ERR_NO_NODE); |
1011 | TIPC_ERR_NO_NODE); | ||
1012 | if (likely(res != -ELINKCONG)) { | 984 | if (likely(res != -ELINKCONG)) { |
1013 | if (res > 0) | 985 | if (res > 0) |
1014 | p_ptr->sent++; | 986 | p_ptr->sent++; |
1015 | return res; | 987 | return res; |
1016 | } | 988 | } |
1017 | if (port_unreliable(p_ptr)) { | 989 | if (port_unreliable(p_ptr)) { |
1018 | return total_len; | 990 | return len; |
1019 | } | 991 | } |
1020 | return -ELINKCONG; | 992 | return -ELINKCONG; |
1021 | } | 993 | } |
1022 | return tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect, | 994 | return tipc_port_reject_sections(p_ptr, msg, msg_sect, len, |
1023 | total_len, TIPC_ERR_NO_NAME); | 995 | TIPC_ERR_NO_NAME); |
1024 | } | 996 | } |
1025 | 997 | ||
1026 | /** | 998 | /** |
1027 | * tipc_send2port - send message sections to port identity | 999 | * tipc_send2port - send message sections to port identity |
1028 | */ | 1000 | */ |
1029 | int tipc_send2port(u32 ref, struct tipc_portid const *dest, | 1001 | int tipc_send2port(u32 ref, struct tipc_portid const *dest, |
1030 | unsigned int num_sect, struct iovec const *msg_sect, | 1002 | struct iovec const *msg_sect, unsigned int len) |
1031 | unsigned int total_len) | ||
1032 | { | 1003 | { |
1033 | struct tipc_port *p_ptr; | 1004 | struct tipc_port *p_ptr; |
1034 | struct tipc_msg *msg; | 1005 | struct tipc_msg *msg; |
@@ -1046,21 +1017,20 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest, | |||
1046 | msg_set_hdr_sz(msg, BASIC_H_SIZE); | 1017 | msg_set_hdr_sz(msg, BASIC_H_SIZE); |
1047 | 1018 | ||
1048 | if (in_own_node(dest->node)) | 1019 | if (in_own_node(dest->node)) |
1049 | res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect, | 1020 | res = tipc_port_recv_sections(p_ptr, msg_sect, len); |
1050 | total_len); | ||
1051 | else if (tipc_own_addr) | 1021 | else if (tipc_own_addr) |
1052 | res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect, | 1022 | res = tipc_link_send_sections_fast(p_ptr, msg_sect, len, |
1053 | total_len, dest->node); | 1023 | dest->node); |
1054 | else | 1024 | else |
1055 | res = tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect, | 1025 | res = tipc_port_reject_sections(p_ptr, msg, msg_sect, len, |
1056 | total_len, TIPC_ERR_NO_NODE); | 1026 | TIPC_ERR_NO_NODE); |
1057 | if (likely(res != -ELINKCONG)) { | 1027 | if (likely(res != -ELINKCONG)) { |
1058 | if (res > 0) | 1028 | if (res > 0) |
1059 | p_ptr->sent++; | 1029 | p_ptr->sent++; |
1060 | return res; | 1030 | return res; |
1061 | } | 1031 | } |
1062 | if (port_unreliable(p_ptr)) { | 1032 | if (port_unreliable(p_ptr)) { |
1063 | return total_len; | 1033 | return len; |
1064 | } | 1034 | } |
1065 | return -ELINKCONG; | 1035 | return -ELINKCONG; |
1066 | } | 1036 | } |
diff --git a/net/tipc/port.h b/net/tipc/port.h index 5a7026b9c345..34f12bd4074e 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h | |||
@@ -116,7 +116,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err); | |||
116 | 116 | ||
117 | void tipc_acknowledge(u32 port_ref, u32 ack); | 117 | void tipc_acknowledge(u32 port_ref, u32 ack); |
118 | 118 | ||
119 | int tipc_deleteport(u32 portref); | 119 | int tipc_deleteport(struct tipc_port *p_ptr); |
120 | 120 | ||
121 | int tipc_portimportance(u32 portref, unsigned int *importance); | 121 | int tipc_portimportance(u32 portref, unsigned int *importance); |
122 | int tipc_set_portimportance(u32 portref, unsigned int importance); | 122 | int tipc_set_portimportance(u32 portref, unsigned int importance); |
@@ -127,9 +127,9 @@ int tipc_set_portunreliable(u32 portref, unsigned int isunreliable); | |||
127 | int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable); | 127 | int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable); |
128 | int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable); | 128 | int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable); |
129 | 129 | ||
130 | int tipc_publish(u32 portref, unsigned int scope, | 130 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, |
131 | struct tipc_name_seq const *name_seq); | 131 | struct tipc_name_seq const *name_seq); |
132 | int tipc_withdraw(u32 portref, unsigned int scope, | 132 | int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope, |
133 | struct tipc_name_seq const *name_seq); | 133 | struct tipc_name_seq const *name_seq); |
134 | 134 | ||
135 | int tipc_connect(u32 portref, struct tipc_portid const *port); | 135 | int tipc_connect(u32 portref, struct tipc_portid const *port); |
@@ -151,24 +151,20 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); | |||
151 | * TIPC messaging routines | 151 | * TIPC messaging routines |
152 | */ | 152 | */ |
153 | int tipc_port_recv_msg(struct sk_buff *buf); | 153 | int tipc_port_recv_msg(struct sk_buff *buf); |
154 | int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect, | 154 | int tipc_send(u32 portref, struct iovec const *msg_sect, unsigned int len); |
155 | unsigned int total_len); | ||
156 | 155 | ||
157 | int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain, | 156 | int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain, |
158 | unsigned int num_sect, struct iovec const *msg_sect, | 157 | struct iovec const *msg_sect, unsigned int len); |
159 | unsigned int total_len); | ||
160 | 158 | ||
161 | int tipc_send2port(u32 portref, struct tipc_portid const *dest, | 159 | int tipc_send2port(u32 portref, struct tipc_portid const *dest, |
162 | unsigned int num_sect, struct iovec const *msg_sect, | 160 | struct iovec const *msg_sect, unsigned int len); |
163 | unsigned int total_len); | ||
164 | 161 | ||
165 | int tipc_multicast(u32 portref, struct tipc_name_seq const *seq, | 162 | int tipc_multicast(u32 portref, struct tipc_name_seq const *seq, |
166 | unsigned int section_count, struct iovec const *msg, | 163 | struct iovec const *msg, unsigned int len); |
167 | unsigned int total_len); | ||
168 | 164 | ||
169 | int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, | 165 | int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, |
170 | struct iovec const *msg_sect, u32 num_sect, | 166 | struct iovec const *msg_sect, unsigned int len, |
171 | unsigned int total_len, int err); | 167 | int err); |
172 | struct sk_buff *tipc_port_get_ports(void); | 168 | struct sk_buff *tipc_port_get_ports(void); |
173 | void tipc_port_recv_proto_msg(struct sk_buff *buf); | 169 | void tipc_port_recv_proto_msg(struct sk_buff *buf); |
174 | void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp); | 170 | void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp); |
diff --git a/net/tipc/server.c b/net/tipc/server.c index fd3fa57a410e..b635ca347a87 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 | */ |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 6cc7ddd2fb7c..aab4948f0aff 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); |
@@ -239,7 +236,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) | 236 | int tipc_sock_create_local(int type, struct socket **res) |
240 | { | 237 | { |
241 | int rc; | 238 | int rc; |
242 | struct sock *sk; | ||
243 | 239 | ||
244 | rc = sock_create_lite(AF_TIPC, type, 0, res); | 240 | rc = sock_create_lite(AF_TIPC, type, 0, res); |
245 | if (rc < 0) { | 241 | if (rc < 0) { |
@@ -248,8 +244,6 @@ int tipc_sock_create_local(int type, struct socket **res) | |||
248 | } | 244 | } |
249 | tipc_sk_create(&init_net, *res, 0, 1); | 245 | tipc_sk_create(&init_net, *res, 0, 1); |
250 | 246 | ||
251 | sk = (*res)->sk; | ||
252 | |||
253 | return 0; | 247 | return 0; |
254 | } | 248 | } |
255 | 249 | ||
@@ -338,7 +332,7 @@ static int release(struct socket *sock) | |||
338 | buf = __skb_dequeue(&sk->sk_receive_queue); | 332 | buf = __skb_dequeue(&sk->sk_receive_queue); |
339 | if (buf == NULL) | 333 | if (buf == NULL) |
340 | break; | 334 | break; |
341 | if (TIPC_SKB_CB(buf)->handle != 0) | 335 | if (TIPC_SKB_CB(buf)->handle != NULL) |
342 | kfree_skb(buf); | 336 | kfree_skb(buf); |
343 | else { | 337 | else { |
344 | if ((sock->state == SS_CONNECTING) || | 338 | if ((sock->state == SS_CONNECTING) || |
@@ -354,7 +348,7 @@ static int release(struct socket *sock) | |||
354 | * Delete TIPC port; this ensures no more messages are queued | 348 | * Delete TIPC port; this ensures no more messages are queued |
355 | * (also disconnects an active connection & sends a 'FIN-' to peer) | 349 | * (also disconnects an active connection & sends a 'FIN-' to peer) |
356 | */ | 350 | */ |
357 | res = tipc_deleteport(tport->ref); | 351 | res = tipc_deleteport(tport); |
358 | 352 | ||
359 | /* Discard any remaining (connection-based) messages in receive queue */ | 353 | /* Discard any remaining (connection-based) messages in receive queue */ |
360 | __skb_queue_purge(&sk->sk_receive_queue); | 354 | __skb_queue_purge(&sk->sk_receive_queue); |
@@ -386,30 +380,46 @@ static int release(struct socket *sock) | |||
386 | */ | 380 | */ |
387 | static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) | 381 | static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) |
388 | { | 382 | { |
383 | struct sock *sk = sock->sk; | ||
389 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; | 384 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; |
390 | u32 portref = tipc_sk_port(sock->sk)->ref; | 385 | struct tipc_port *tport = tipc_sk_port(sock->sk); |
386 | int res = -EINVAL; | ||
391 | 387 | ||
392 | if (unlikely(!uaddr_len)) | 388 | lock_sock(sk); |
393 | return tipc_withdraw(portref, 0, NULL); | 389 | if (unlikely(!uaddr_len)) { |
390 | res = tipc_withdraw(tport, 0, NULL); | ||
391 | goto exit; | ||
392 | } | ||
394 | 393 | ||
395 | if (uaddr_len < sizeof(struct sockaddr_tipc)) | 394 | if (uaddr_len < sizeof(struct sockaddr_tipc)) { |
396 | return -EINVAL; | 395 | res = -EINVAL; |
397 | if (addr->family != AF_TIPC) | 396 | goto exit; |
398 | return -EAFNOSUPPORT; | 397 | } |
398 | if (addr->family != AF_TIPC) { | ||
399 | res = -EAFNOSUPPORT; | ||
400 | goto exit; | ||
401 | } | ||
399 | 402 | ||
400 | if (addr->addrtype == TIPC_ADDR_NAME) | 403 | if (addr->addrtype == TIPC_ADDR_NAME) |
401 | addr->addr.nameseq.upper = addr->addr.nameseq.lower; | 404 | addr->addr.nameseq.upper = addr->addr.nameseq.lower; |
402 | else if (addr->addrtype != TIPC_ADDR_NAMESEQ) | 405 | else if (addr->addrtype != TIPC_ADDR_NAMESEQ) { |
403 | return -EAFNOSUPPORT; | 406 | res = -EAFNOSUPPORT; |
407 | goto exit; | ||
408 | } | ||
404 | 409 | ||
405 | if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) && | 410 | if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) && |
406 | (addr->addr.nameseq.type != TIPC_TOP_SRV) && | 411 | (addr->addr.nameseq.type != TIPC_TOP_SRV) && |
407 | (addr->addr.nameseq.type != TIPC_CFG_SRV)) | 412 | (addr->addr.nameseq.type != TIPC_CFG_SRV)) { |
408 | return -EACCES; | 413 | res = -EACCES; |
414 | goto exit; | ||
415 | } | ||
409 | 416 | ||
410 | return (addr->scope > 0) ? | 417 | res = (addr->scope > 0) ? |
411 | tipc_publish(portref, addr->scope, &addr->addr.nameseq) : | 418 | tipc_publish(tport, addr->scope, &addr->addr.nameseq) : |
412 | tipc_withdraw(portref, -addr->scope, &addr->addr.nameseq); | 419 | tipc_withdraw(tport, -addr->scope, &addr->addr.nameseq); |
420 | exit: | ||
421 | release_sock(sk); | ||
422 | return res; | ||
413 | } | 423 | } |
414 | 424 | ||
415 | /** | 425 | /** |
@@ -554,6 +564,31 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | |||
554 | return 0; | 564 | return 0; |
555 | } | 565 | } |
556 | 566 | ||
567 | static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | ||
568 | { | ||
569 | struct sock *sk = sock->sk; | ||
570 | struct tipc_port *tport = tipc_sk_port(sk); | ||
571 | DEFINE_WAIT(wait); | ||
572 | int done; | ||
573 | |||
574 | do { | ||
575 | int err = sock_error(sk); | ||
576 | if (err) | ||
577 | return err; | ||
578 | if (sock->state == SS_DISCONNECTING) | ||
579 | return -EPIPE; | ||
580 | if (!*timeo_p) | ||
581 | return -EAGAIN; | ||
582 | if (signal_pending(current)) | ||
583 | return sock_intr_errno(*timeo_p); | ||
584 | |||
585 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
586 | done = sk_wait_event(sk, timeo_p, !tport->congested); | ||
587 | finish_wait(sk_sleep(sk), &wait); | ||
588 | } while (!done); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
557 | /** | 592 | /** |
558 | * send_msg - send message in connectionless manner | 593 | * send_msg - send message in connectionless manner |
559 | * @iocb: if NULL, indicates that socket lock is already held | 594 | * @iocb: if NULL, indicates that socket lock is already held |
@@ -573,9 +608,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
573 | { | 608 | { |
574 | struct sock *sk = sock->sk; | 609 | struct sock *sk = sock->sk; |
575 | struct tipc_port *tport = tipc_sk_port(sk); | 610 | struct tipc_port *tport = tipc_sk_port(sk); |
576 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 611 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
577 | int needs_conn; | 612 | int needs_conn; |
578 | long timeout_val; | 613 | long timeo; |
579 | int res = -EINVAL; | 614 | int res = -EINVAL; |
580 | 615 | ||
581 | if (unlikely(!dest)) | 616 | if (unlikely(!dest)) |
@@ -612,8 +647,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
612 | reject_rx_queue(sk); | 647 | reject_rx_queue(sk); |
613 | } | 648 | } |
614 | 649 | ||
615 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 650 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
616 | |||
617 | do { | 651 | do { |
618 | if (dest->addrtype == TIPC_ADDR_NAME) { | 652 | if (dest->addrtype == TIPC_ADDR_NAME) { |
619 | res = dest_name_check(dest, m); | 653 | res = dest_name_check(dest, m); |
@@ -622,13 +656,11 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
622 | res = tipc_send2name(tport->ref, | 656 | res = tipc_send2name(tport->ref, |
623 | &dest->addr.name.name, | 657 | &dest->addr.name.name, |
624 | dest->addr.name.domain, | 658 | dest->addr.name.domain, |
625 | m->msg_iovlen, | ||
626 | m->msg_iov, | 659 | m->msg_iov, |
627 | total_len); | 660 | total_len); |
628 | } else if (dest->addrtype == TIPC_ADDR_ID) { | 661 | } else if (dest->addrtype == TIPC_ADDR_ID) { |
629 | res = tipc_send2port(tport->ref, | 662 | res = tipc_send2port(tport->ref, |
630 | &dest->addr.id, | 663 | &dest->addr.id, |
631 | m->msg_iovlen, | ||
632 | m->msg_iov, | 664 | m->msg_iov, |
633 | total_len); | 665 | total_len); |
634 | } else if (dest->addrtype == TIPC_ADDR_MCAST) { | 666 | } else if (dest->addrtype == TIPC_ADDR_MCAST) { |
@@ -641,7 +673,6 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
641 | break; | 673 | break; |
642 | res = tipc_multicast(tport->ref, | 674 | res = tipc_multicast(tport->ref, |
643 | &dest->addr.nameseq, | 675 | &dest->addr.nameseq, |
644 | m->msg_iovlen, | ||
645 | m->msg_iov, | 676 | m->msg_iov, |
646 | total_len); | 677 | total_len); |
647 | } | 678 | } |
@@ -650,14 +681,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
650 | sock->state = SS_CONNECTING; | 681 | sock->state = SS_CONNECTING; |
651 | break; | 682 | break; |
652 | } | 683 | } |
653 | if (timeout_val <= 0L) { | 684 | res = tipc_wait_for_sndmsg(sock, &timeo); |
654 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 685 | if (res) |
655 | break; | 686 | break; |
656 | } | ||
657 | release_sock(sk); | ||
658 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
659 | !tport->congested, timeout_val); | ||
660 | lock_sock(sk); | ||
661 | } while (1); | 687 | } while (1); |
662 | 688 | ||
663 | exit: | 689 | exit: |
@@ -666,6 +692,34 @@ exit: | |||
666 | return res; | 692 | return res; |
667 | } | 693 | } |
668 | 694 | ||
695 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | ||
696 | { | ||
697 | struct sock *sk = sock->sk; | ||
698 | struct tipc_port *tport = tipc_sk_port(sk); | ||
699 | DEFINE_WAIT(wait); | ||
700 | int done; | ||
701 | |||
702 | do { | ||
703 | int err = sock_error(sk); | ||
704 | if (err) | ||
705 | return err; | ||
706 | if (sock->state == SS_DISCONNECTING) | ||
707 | return -EPIPE; | ||
708 | else if (sock->state != SS_CONNECTED) | ||
709 | return -ENOTCONN; | ||
710 | if (!*timeo_p) | ||
711 | return -EAGAIN; | ||
712 | if (signal_pending(current)) | ||
713 | return sock_intr_errno(*timeo_p); | ||
714 | |||
715 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
716 | done = sk_wait_event(sk, timeo_p, | ||
717 | (!tport->congested || !tport->connected)); | ||
718 | finish_wait(sk_sleep(sk), &wait); | ||
719 | } while (!done); | ||
720 | return 0; | ||
721 | } | ||
722 | |||
669 | /** | 723 | /** |
670 | * send_packet - send a connection-oriented message | 724 | * send_packet - send a connection-oriented message |
671 | * @iocb: if NULL, indicates that socket lock is already held | 725 | * @iocb: if NULL, indicates that socket lock is already held |
@@ -682,9 +736,9 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
682 | { | 736 | { |
683 | struct sock *sk = sock->sk; | 737 | struct sock *sk = sock->sk; |
684 | struct tipc_port *tport = tipc_sk_port(sk); | 738 | struct tipc_port *tport = tipc_sk_port(sk); |
685 | struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; | 739 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
686 | long timeout_val; | 740 | int res = -EINVAL; |
687 | int res; | 741 | long timeo; |
688 | 742 | ||
689 | /* Handle implied connection establishment */ | 743 | /* Handle implied connection establishment */ |
690 | if (unlikely(dest)) | 744 | if (unlikely(dest)) |
@@ -696,31 +750,24 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
696 | if (iocb) | 750 | if (iocb) |
697 | lock_sock(sk); | 751 | lock_sock(sk); |
698 | 752 | ||
699 | timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 753 | if (unlikely(sock->state != SS_CONNECTED)) { |
754 | if (sock->state == SS_DISCONNECTING) | ||
755 | res = -EPIPE; | ||
756 | else | ||
757 | res = -ENOTCONN; | ||
758 | goto exit; | ||
759 | } | ||
700 | 760 | ||
761 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | ||
701 | do { | 762 | do { |
702 | if (unlikely(sock->state != SS_CONNECTED)) { | 763 | res = tipc_send(tport->ref, m->msg_iov, total_len); |
703 | if (sock->state == SS_DISCONNECTING) | ||
704 | res = -EPIPE; | ||
705 | else | ||
706 | res = -ENOTCONN; | ||
707 | break; | ||
708 | } | ||
709 | |||
710 | res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov, | ||
711 | total_len); | ||
712 | if (likely(res != -ELINKCONG)) | 764 | if (likely(res != -ELINKCONG)) |
713 | break; | 765 | break; |
714 | if (timeout_val <= 0L) { | 766 | res = tipc_wait_for_sndpkt(sock, &timeo); |
715 | res = timeout_val ? timeout_val : -EWOULDBLOCK; | 767 | if (res) |
716 | break; | 768 | break; |
717 | } | ||
718 | release_sock(sk); | ||
719 | timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
720 | (!tport->congested || !tport->connected), timeout_val); | ||
721 | lock_sock(sk); | ||
722 | } while (1); | 769 | } while (1); |
723 | 770 | exit: | |
724 | if (iocb) | 771 | if (iocb) |
725 | release_sock(sk); | 772 | release_sock(sk); |
726 | return res; | 773 | return res; |
@@ -758,16 +805,11 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, | |||
758 | 805 | ||
759 | /* Handle special cases where there is no connection */ | 806 | /* Handle special cases where there is no connection */ |
760 | if (unlikely(sock->state != SS_CONNECTED)) { | 807 | if (unlikely(sock->state != SS_CONNECTED)) { |
761 | if (sock->state == SS_UNCONNECTED) { | 808 | if (sock->state == SS_UNCONNECTED) |
762 | res = send_packet(NULL, sock, m, total_len); | 809 | res = send_packet(NULL, sock, m, total_len); |
763 | goto exit; | 810 | else |
764 | } else if (sock->state == SS_DISCONNECTING) { | 811 | res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; |
765 | res = -EPIPE; | 812 | goto exit; |
766 | goto exit; | ||
767 | } else { | ||
768 | res = -ENOTCONN; | ||
769 | goto exit; | ||
770 | } | ||
771 | } | 813 | } |
772 | 814 | ||
773 | if (unlikely(m->msg_name)) { | 815 | if (unlikely(m->msg_name)) { |
@@ -864,7 +906,7 @@ static int auto_connect(struct socket *sock, struct tipc_msg *msg) | |||
864 | */ | 906 | */ |
865 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | 907 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) |
866 | { | 908 | { |
867 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; | 909 | DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name); |
868 | 910 | ||
869 | if (addr) { | 911 | if (addr) { |
870 | addr->family = AF_TIPC; | 912 | addr->family = AF_TIPC; |
@@ -949,6 +991,37 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | |||
949 | return 0; | 991 | return 0; |
950 | } | 992 | } |
951 | 993 | ||
994 | static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo) | ||
995 | { | ||
996 | struct sock *sk = sock->sk; | ||
997 | DEFINE_WAIT(wait); | ||
998 | int err; | ||
999 | |||
1000 | for (;;) { | ||
1001 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
1002 | if (skb_queue_empty(&sk->sk_receive_queue)) { | ||
1003 | if (sock->state == SS_DISCONNECTING) { | ||
1004 | err = -ENOTCONN; | ||
1005 | break; | ||
1006 | } | ||
1007 | release_sock(sk); | ||
1008 | timeo = schedule_timeout(timeo); | ||
1009 | lock_sock(sk); | ||
1010 | } | ||
1011 | err = 0; | ||
1012 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
1013 | break; | ||
1014 | err = sock_intr_errno(timeo); | ||
1015 | if (signal_pending(current)) | ||
1016 | break; | ||
1017 | err = -EAGAIN; | ||
1018 | if (!timeo) | ||
1019 | break; | ||
1020 | } | ||
1021 | finish_wait(sk_sleep(sk), &wait); | ||
1022 | return err; | ||
1023 | } | ||
1024 | |||
952 | /** | 1025 | /** |
953 | * recv_msg - receive packet-oriented message | 1026 | * recv_msg - receive packet-oriented message |
954 | * @iocb: (unused) | 1027 | * @iocb: (unused) |
@@ -968,7 +1041,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
968 | struct tipc_port *tport = tipc_sk_port(sk); | 1041 | struct tipc_port *tport = tipc_sk_port(sk); |
969 | struct sk_buff *buf; | 1042 | struct sk_buff *buf; |
970 | struct tipc_msg *msg; | 1043 | struct tipc_msg *msg; |
971 | long timeout; | 1044 | long timeo; |
972 | unsigned int sz; | 1045 | unsigned int sz; |
973 | u32 err; | 1046 | u32 err; |
974 | int res; | 1047 | int res; |
@@ -984,28 +1057,13 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, | |||
984 | goto exit; | 1057 | goto exit; |
985 | } | 1058 | } |
986 | 1059 | ||
987 | /* will be updated in set_orig_addr() if needed */ | 1060 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
988 | m->msg_namelen = 0; | ||
989 | |||
990 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | ||
991 | restart: | 1061 | restart: |
992 | 1062 | ||
993 | /* Look for a message in receive queue; wait if necessary */ | 1063 | /* Look for a message in receive queue; wait if necessary */ |
994 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1064 | res = tipc_wait_for_rcvmsg(sock, timeo); |
995 | if (sock->state == SS_DISCONNECTING) { | 1065 | if (res) |
996 | res = -ENOTCONN; | 1066 | goto exit; |
997 | goto exit; | ||
998 | } | ||
999 | if (timeout <= 0L) { | ||
1000 | res = timeout ? timeout : -EWOULDBLOCK; | ||
1001 | goto exit; | ||
1002 | } | ||
1003 | release_sock(sk); | ||
1004 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
1005 | tipc_rx_ready(sock), | ||
1006 | timeout); | ||
1007 | lock_sock(sk); | ||
1008 | } | ||
1009 | 1067 | ||
1010 | /* Look at first message in receive queue */ | 1068 | /* Look at first message in receive queue */ |
1011 | buf = skb_peek(&sk->sk_receive_queue); | 1069 | buf = skb_peek(&sk->sk_receive_queue); |
@@ -1077,7 +1135,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
1077 | struct tipc_port *tport = tipc_sk_port(sk); | 1135 | struct tipc_port *tport = tipc_sk_port(sk); |
1078 | struct sk_buff *buf; | 1136 | struct sk_buff *buf; |
1079 | struct tipc_msg *msg; | 1137 | struct tipc_msg *msg; |
1080 | long timeout; | 1138 | long timeo; |
1081 | unsigned int sz; | 1139 | unsigned int sz; |
1082 | int sz_to_copy, target, needed; | 1140 | int sz_to_copy, target, needed; |
1083 | int sz_copied = 0; | 1141 | int sz_copied = 0; |
@@ -1090,34 +1148,19 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, | |||
1090 | 1148 | ||
1091 | lock_sock(sk); | 1149 | lock_sock(sk); |
1092 | 1150 | ||
1093 | if (unlikely((sock->state == SS_UNCONNECTED))) { | 1151 | if (unlikely(sock->state == SS_UNCONNECTED)) { |
1094 | res = -ENOTCONN; | 1152 | res = -ENOTCONN; |
1095 | goto exit; | 1153 | goto exit; |
1096 | } | 1154 | } |
1097 | 1155 | ||
1098 | /* will be updated in set_orig_addr() if needed */ | ||
1099 | m->msg_namelen = 0; | ||
1100 | |||
1101 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); | 1156 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); |
1102 | timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); | 1157 | timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); |
1103 | 1158 | ||
1104 | restart: | 1159 | restart: |
1105 | /* Look for a message in receive queue; wait if necessary */ | 1160 | /* Look for a message in receive queue; wait if necessary */ |
1106 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1161 | res = tipc_wait_for_rcvmsg(sock, timeo); |
1107 | if (sock->state == SS_DISCONNECTING) { | 1162 | if (res) |
1108 | res = -ENOTCONN; | 1163 | goto exit; |
1109 | goto exit; | ||
1110 | } | ||
1111 | if (timeout <= 0L) { | ||
1112 | res = timeout ? timeout : -EWOULDBLOCK; | ||
1113 | goto exit; | ||
1114 | } | ||
1115 | release_sock(sk); | ||
1116 | timeout = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
1117 | tipc_rx_ready(sock), | ||
1118 | timeout); | ||
1119 | lock_sock(sk); | ||
1120 | } | ||
1121 | 1164 | ||
1122 | /* Look at first message in receive queue */ | 1165 | /* Look at first message in receive queue */ |
1123 | buf = skb_peek(&sk->sk_receive_queue); | 1166 | buf = skb_peek(&sk->sk_receive_queue); |
@@ -1321,14 +1364,12 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf) | |||
1321 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) | 1364 | static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) |
1322 | { | 1365 | { |
1323 | struct tipc_msg *msg = buf_msg(buf); | 1366 | struct tipc_msg *msg = buf_msg(buf); |
1324 | unsigned int limit; | ||
1325 | 1367 | ||
1326 | if (msg_connected(msg)) | 1368 | if (msg_connected(msg)) |
1327 | limit = sysctl_tipc_rmem[2]; | 1369 | return sysctl_tipc_rmem[2]; |
1328 | else | 1370 | |
1329 | limit = sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << | 1371 | return sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE << |
1330 | msg_importance(msg); | 1372 | msg_importance(msg); |
1331 | return limit; | ||
1332 | } | 1373 | } |
1333 | 1374 | ||
1334 | /** | 1375 | /** |
@@ -1368,7 +1409,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | |||
1368 | return TIPC_ERR_OVERLOAD; | 1409 | return TIPC_ERR_OVERLOAD; |
1369 | 1410 | ||
1370 | /* Enqueue message */ | 1411 | /* Enqueue message */ |
1371 | TIPC_SKB_CB(buf)->handle = 0; | 1412 | TIPC_SKB_CB(buf)->handle = NULL; |
1372 | __skb_queue_tail(&sk->sk_receive_queue, buf); | 1413 | __skb_queue_tail(&sk->sk_receive_queue, buf); |
1373 | skb_set_owner_r(buf, sk); | 1414 | skb_set_owner_r(buf, sk); |
1374 | 1415 | ||
@@ -1442,6 +1483,28 @@ static void wakeupdispatch(struct tipc_port *tport) | |||
1442 | sk->sk_write_space(sk); | 1483 | sk->sk_write_space(sk); |
1443 | } | 1484 | } |
1444 | 1485 | ||
1486 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) | ||
1487 | { | ||
1488 | struct sock *sk = sock->sk; | ||
1489 | DEFINE_WAIT(wait); | ||
1490 | int done; | ||
1491 | |||
1492 | do { | ||
1493 | int err = sock_error(sk); | ||
1494 | if (err) | ||
1495 | return err; | ||
1496 | if (!*timeo_p) | ||
1497 | return -ETIMEDOUT; | ||
1498 | if (signal_pending(current)) | ||
1499 | return sock_intr_errno(*timeo_p); | ||
1500 | |||
1501 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
1502 | done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); | ||
1503 | finish_wait(sk_sleep(sk), &wait); | ||
1504 | } while (!done); | ||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1445 | /** | 1508 | /** |
1446 | * connect - establish a connection to another TIPC port | 1509 | * connect - establish a connection to another TIPC port |
1447 | * @sock: socket structure | 1510 | * @sock: socket structure |
@@ -1457,7 +1520,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
1457 | struct sock *sk = sock->sk; | 1520 | struct sock *sk = sock->sk; |
1458 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; | 1521 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; |
1459 | struct msghdr m = {NULL,}; | 1522 | struct msghdr m = {NULL,}; |
1460 | unsigned int timeout; | 1523 | long timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; |
1524 | socket_state previous; | ||
1461 | int res; | 1525 | int res; |
1462 | 1526 | ||
1463 | lock_sock(sk); | 1527 | lock_sock(sk); |
@@ -1479,8 +1543,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
1479 | goto exit; | 1543 | goto exit; |
1480 | } | 1544 | } |
1481 | 1545 | ||
1482 | timeout = (flags & O_NONBLOCK) ? 0 : tipc_sk(sk)->conn_timeout; | 1546 | previous = sock->state; |
1483 | |||
1484 | switch (sock->state) { | 1547 | switch (sock->state) { |
1485 | case SS_UNCONNECTED: | 1548 | case SS_UNCONNECTED: |
1486 | /* Send a 'SYN-' to destination */ | 1549 | /* Send a 'SYN-' to destination */ |
@@ -1502,43 +1565,22 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
1502 | * case is EINPROGRESS, rather than EALREADY. | 1565 | * case is EINPROGRESS, rather than EALREADY. |
1503 | */ | 1566 | */ |
1504 | res = -EINPROGRESS; | 1567 | res = -EINPROGRESS; |
1505 | break; | ||
1506 | case SS_CONNECTING: | 1568 | case SS_CONNECTING: |
1507 | res = -EALREADY; | 1569 | if (previous == SS_CONNECTING) |
1570 | res = -EALREADY; | ||
1571 | if (!timeout) | ||
1572 | goto exit; | ||
1573 | timeout = msecs_to_jiffies(timeout); | ||
1574 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
1575 | res = tipc_wait_for_connect(sock, &timeout); | ||
1508 | break; | 1576 | break; |
1509 | case SS_CONNECTED: | 1577 | case SS_CONNECTED: |
1510 | res = -EISCONN; | 1578 | res = -EISCONN; |
1511 | break; | 1579 | break; |
1512 | default: | 1580 | default: |
1513 | res = -EINVAL; | 1581 | res = -EINVAL; |
1514 | goto exit; | 1582 | break; |
1515 | } | ||
1516 | |||
1517 | if (sock->state == SS_CONNECTING) { | ||
1518 | if (!timeout) | ||
1519 | goto exit; | ||
1520 | |||
1521 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | ||
1522 | release_sock(sk); | ||
1523 | res = wait_event_interruptible_timeout(*sk_sleep(sk), | ||
1524 | sock->state != SS_CONNECTING, | ||
1525 | timeout ? (long)msecs_to_jiffies(timeout) | ||
1526 | : MAX_SCHEDULE_TIMEOUT); | ||
1527 | lock_sock(sk); | ||
1528 | if (res <= 0) { | ||
1529 | if (res == 0) | ||
1530 | res = -ETIMEDOUT; | ||
1531 | else | ||
1532 | ; /* leave "res" unchanged */ | ||
1533 | goto exit; | ||
1534 | } | ||
1535 | } | 1583 | } |
1536 | |||
1537 | if (unlikely(sock->state == SS_DISCONNECTING)) | ||
1538 | res = sock_error(sk); | ||
1539 | else | ||
1540 | res = 0; | ||
1541 | |||
1542 | exit: | 1584 | exit: |
1543 | release_sock(sk); | 1585 | release_sock(sk); |
1544 | return res; | 1586 | return res; |
@@ -1569,6 +1611,42 @@ static int listen(struct socket *sock, int len) | |||
1569 | return res; | 1611 | return res; |
1570 | } | 1612 | } |
1571 | 1613 | ||
1614 | static int tipc_wait_for_accept(struct socket *sock, long timeo) | ||
1615 | { | ||
1616 | struct sock *sk = sock->sk; | ||
1617 | DEFINE_WAIT(wait); | ||
1618 | int err; | ||
1619 | |||
1620 | /* True wake-one mechanism for incoming connections: only | ||
1621 | * one process gets woken up, not the 'whole herd'. | ||
1622 | * Since we do not 'race & poll' for established sockets | ||
1623 | * anymore, the common case will execute the loop only once. | ||
1624 | */ | ||
1625 | for (;;) { | ||
1626 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, | ||
1627 | TASK_INTERRUPTIBLE); | ||
1628 | if (skb_queue_empty(&sk->sk_receive_queue)) { | ||
1629 | release_sock(sk); | ||
1630 | timeo = schedule_timeout(timeo); | ||
1631 | lock_sock(sk); | ||
1632 | } | ||
1633 | err = 0; | ||
1634 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
1635 | break; | ||
1636 | err = -EINVAL; | ||
1637 | if (sock->state != SS_LISTENING) | ||
1638 | break; | ||
1639 | err = sock_intr_errno(timeo); | ||
1640 | if (signal_pending(current)) | ||
1641 | break; | ||
1642 | err = -EAGAIN; | ||
1643 | if (!timeo) | ||
1644 | break; | ||
1645 | } | ||
1646 | finish_wait(sk_sleep(sk), &wait); | ||
1647 | return err; | ||
1648 | } | ||
1649 | |||
1572 | /** | 1650 | /** |
1573 | * accept - wait for connection request | 1651 | * accept - wait for connection request |
1574 | * @sock: listening socket | 1652 | * @sock: listening socket |
@@ -1585,7 +1663,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
1585 | struct tipc_port *new_tport; | 1663 | struct tipc_port *new_tport; |
1586 | struct tipc_msg *msg; | 1664 | struct tipc_msg *msg; |
1587 | u32 new_ref; | 1665 | u32 new_ref; |
1588 | 1666 | long timeo; | |
1589 | int res; | 1667 | int res; |
1590 | 1668 | ||
1591 | lock_sock(sk); | 1669 | lock_sock(sk); |
@@ -1595,18 +1673,10 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
1595 | goto exit; | 1673 | goto exit; |
1596 | } | 1674 | } |
1597 | 1675 | ||
1598 | while (skb_queue_empty(&sk->sk_receive_queue)) { | 1676 | timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); |
1599 | if (flags & O_NONBLOCK) { | 1677 | res = tipc_wait_for_accept(sock, timeo); |
1600 | res = -EWOULDBLOCK; | 1678 | if (res) |
1601 | goto exit; | 1679 | goto exit; |
1602 | } | ||
1603 | release_sock(sk); | ||
1604 | res = wait_event_interruptible(*sk_sleep(sk), | ||
1605 | (!skb_queue_empty(&sk->sk_receive_queue))); | ||
1606 | lock_sock(sk); | ||
1607 | if (res) | ||
1608 | goto exit; | ||
1609 | } | ||
1610 | 1680 | ||
1611 | buf = skb_peek(&sk->sk_receive_queue); | 1681 | buf = skb_peek(&sk->sk_receive_queue); |
1612 | 1682 | ||
@@ -1691,7 +1761,7 @@ restart: | |||
1691 | /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ | 1761 | /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ |
1692 | buf = __skb_dequeue(&sk->sk_receive_queue); | 1762 | buf = __skb_dequeue(&sk->sk_receive_queue); |
1693 | if (buf) { | 1763 | if (buf) { |
1694 | if (TIPC_SKB_CB(buf)->handle != 0) { | 1764 | if (TIPC_SKB_CB(buf)->handle != NULL) { |
1695 | kfree_skb(buf); | 1765 | kfree_skb(buf); |
1696 | goto restart; | 1766 | goto restart; |
1697 | } | 1767 | } |
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index d38bb45d82e9..7cb0bd5b1176 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 { |