diff options
Diffstat (limited to 'net/tipc/port.c')
-rw-r--r-- | net/tipc/port.c | 440 |
1 files changed, 28 insertions, 412 deletions
diff --git a/net/tipc/port.c b/net/tipc/port.c index 5fd7acce01ea..7e096a5e7701 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
@@ -42,8 +42,6 @@ | |||
42 | 42 | ||
43 | /* Connection management: */ | 43 | /* Connection management: */ |
44 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ | 44 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ |
45 | #define CONFIRMED 0 | ||
46 | #define PROBING 1 | ||
47 | 45 | ||
48 | #define MAX_REJECT_SIZE 1024 | 46 | #define MAX_REJECT_SIZE 1024 |
49 | 47 | ||
@@ -76,124 +74,6 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) | |||
76 | (!peernode && (orignode == tipc_own_addr)); | 74 | (!peernode && (orignode == tipc_own_addr)); |
77 | } | 75 | } |
78 | 76 | ||
79 | /** | ||
80 | * tipc_port_mcast_xmit - send a multicast message to local and remote | ||
81 | * destinations | ||
82 | */ | ||
83 | int tipc_port_mcast_xmit(struct tipc_port *oport, | ||
84 | struct tipc_name_seq const *seq, | ||
85 | struct iovec const *msg_sect, | ||
86 | unsigned int len) | ||
87 | { | ||
88 | struct tipc_msg *hdr; | ||
89 | struct sk_buff *buf; | ||
90 | struct sk_buff *ibuf = NULL; | ||
91 | struct tipc_port_list dports = {0, NULL, }; | ||
92 | int ext_targets; | ||
93 | int res; | ||
94 | |||
95 | /* Create multicast message */ | ||
96 | hdr = &oport->phdr; | ||
97 | msg_set_type(hdr, TIPC_MCAST_MSG); | ||
98 | msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE); | ||
99 | msg_set_destport(hdr, 0); | ||
100 | msg_set_destnode(hdr, 0); | ||
101 | msg_set_nametype(hdr, seq->type); | ||
102 | msg_set_namelower(hdr, seq->lower); | ||
103 | msg_set_nameupper(hdr, seq->upper); | ||
104 | msg_set_hdr_sz(hdr, MCAST_H_SIZE); | ||
105 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
106 | if (unlikely(!buf)) | ||
107 | return res; | ||
108 | |||
109 | /* Figure out where to send multicast message */ | ||
110 | ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper, | ||
111 | TIPC_NODE_SCOPE, &dports); | ||
112 | |||
113 | /* Send message to destinations (duplicate it only if necessary) */ | ||
114 | if (ext_targets) { | ||
115 | if (dports.count != 0) { | ||
116 | ibuf = skb_copy(buf, GFP_ATOMIC); | ||
117 | if (ibuf == NULL) { | ||
118 | tipc_port_list_free(&dports); | ||
119 | kfree_skb(buf); | ||
120 | return -ENOMEM; | ||
121 | } | ||
122 | } | ||
123 | res = tipc_bclink_xmit(buf); | ||
124 | if ((res < 0) && (dports.count != 0)) | ||
125 | kfree_skb(ibuf); | ||
126 | } else { | ||
127 | ibuf = buf; | ||
128 | } | ||
129 | |||
130 | if (res >= 0) { | ||
131 | if (ibuf) | ||
132 | tipc_port_mcast_rcv(ibuf, &dports); | ||
133 | } else { | ||
134 | tipc_port_list_free(&dports); | ||
135 | } | ||
136 | return res; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * tipc_port_mcast_rcv - deliver multicast message to all destination ports | ||
141 | * | ||
142 | * If there is no port list, perform a lookup to create one | ||
143 | */ | ||
144 | void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp) | ||
145 | { | ||
146 | struct tipc_msg *msg; | ||
147 | struct tipc_port_list dports = {0, NULL, }; | ||
148 | struct tipc_port_list *item = dp; | ||
149 | int cnt = 0; | ||
150 | |||
151 | msg = buf_msg(buf); | ||
152 | |||
153 | /* Create destination port list, if one wasn't supplied */ | ||
154 | if (dp == NULL) { | ||
155 | tipc_nametbl_mc_translate(msg_nametype(msg), | ||
156 | msg_namelower(msg), | ||
157 | msg_nameupper(msg), | ||
158 | TIPC_CLUSTER_SCOPE, | ||
159 | &dports); | ||
160 | item = dp = &dports; | ||
161 | } | ||
162 | |||
163 | /* Deliver a copy of message to each destination port */ | ||
164 | if (dp->count != 0) { | ||
165 | msg_set_destnode(msg, tipc_own_addr); | ||
166 | if (dp->count == 1) { | ||
167 | msg_set_destport(msg, dp->ports[0]); | ||
168 | tipc_sk_rcv(buf); | ||
169 | tipc_port_list_free(dp); | ||
170 | return; | ||
171 | } | ||
172 | for (; cnt < dp->count; cnt++) { | ||
173 | int index = cnt % PLSIZE; | ||
174 | struct sk_buff *b = skb_clone(buf, GFP_ATOMIC); | ||
175 | |||
176 | if (b == NULL) { | ||
177 | pr_warn("Unable to deliver multicast message(s)\n"); | ||
178 | goto exit; | ||
179 | } | ||
180 | if ((index == 0) && (cnt != 0)) | ||
181 | item = item->next; | ||
182 | msg_set_destport(buf_msg(b), item->ports[index]); | ||
183 | tipc_sk_rcv(b); | ||
184 | } | ||
185 | } | ||
186 | exit: | ||
187 | kfree_skb(buf); | ||
188 | tipc_port_list_free(dp); | ||
189 | } | ||
190 | |||
191 | |||
192 | void tipc_port_wakeup(struct tipc_port *port) | ||
193 | { | ||
194 | tipc_sock_wakeup(tipc_port_to_sock(port)); | ||
195 | } | ||
196 | |||
197 | /* tipc_port_init - intiate TIPC port and lock it | 77 | /* tipc_port_init - intiate TIPC port and lock it |
198 | * | 78 | * |
199 | * Returns obtained reference if initialization is successful, zero otherwise | 79 | * Returns obtained reference if initialization is successful, zero otherwise |
@@ -235,6 +115,8 @@ u32 tipc_port_init(struct tipc_port *p_ptr, | |||
235 | void tipc_port_destroy(struct tipc_port *p_ptr) | 115 | void tipc_port_destroy(struct tipc_port *p_ptr) |
236 | { | 116 | { |
237 | struct sk_buff *buf = NULL; | 117 | struct sk_buff *buf = NULL; |
118 | struct tipc_msg *msg = NULL; | ||
119 | u32 peer; | ||
238 | 120 | ||
239 | tipc_withdraw(p_ptr, 0, NULL); | 121 | tipc_withdraw(p_ptr, 0, NULL); |
240 | 122 | ||
@@ -246,14 +128,15 @@ void tipc_port_destroy(struct tipc_port *p_ptr) | |||
246 | if (p_ptr->connected) { | 128 | if (p_ptr->connected) { |
247 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); | 129 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); |
248 | tipc_nodesub_unsubscribe(&p_ptr->subscription); | 130 | tipc_nodesub_unsubscribe(&p_ptr->subscription); |
131 | msg = buf_msg(buf); | ||
132 | peer = msg_destnode(msg); | ||
133 | tipc_link_xmit(buf, peer, msg_link_selector(msg)); | ||
249 | } | 134 | } |
250 | |||
251 | spin_lock_bh(&tipc_port_list_lock); | 135 | spin_lock_bh(&tipc_port_list_lock); |
252 | list_del(&p_ptr->port_list); | 136 | list_del(&p_ptr->port_list); |
253 | list_del(&p_ptr->wait_list); | 137 | list_del(&p_ptr->wait_list); |
254 | spin_unlock_bh(&tipc_port_list_lock); | 138 | spin_unlock_bh(&tipc_port_list_lock); |
255 | k_term_timer(&p_ptr->timer); | 139 | k_term_timer(&p_ptr->timer); |
256 | tipc_net_route_msg(buf); | ||
257 | } | 140 | } |
258 | 141 | ||
259 | /* | 142 | /* |
@@ -275,100 +158,16 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, | |||
275 | msg_set_destport(msg, tipc_port_peerport(p_ptr)); | 158 | msg_set_destport(msg, tipc_port_peerport(p_ptr)); |
276 | msg_set_origport(msg, p_ptr->ref); | 159 | msg_set_origport(msg, p_ptr->ref); |
277 | msg_set_msgcnt(msg, ack); | 160 | msg_set_msgcnt(msg, ack); |
161 | buf->next = NULL; | ||
278 | } | 162 | } |
279 | return buf; | 163 | return buf; |
280 | } | 164 | } |
281 | 165 | ||
282 | int tipc_reject_msg(struct sk_buff *buf, u32 err) | ||
283 | { | ||
284 | struct tipc_msg *msg = buf_msg(buf); | ||
285 | struct sk_buff *rbuf; | ||
286 | struct tipc_msg *rmsg; | ||
287 | int hdr_sz; | ||
288 | u32 imp; | ||
289 | u32 data_sz = msg_data_sz(msg); | ||
290 | u32 src_node; | ||
291 | u32 rmsg_sz; | ||
292 | |||
293 | /* discard rejected message if it shouldn't be returned to sender */ | ||
294 | if (WARN(!msg_isdata(msg), | ||
295 | "attempt to reject message with user=%u", msg_user(msg))) { | ||
296 | dump_stack(); | ||
297 | goto exit; | ||
298 | } | ||
299 | if (msg_errcode(msg) || msg_dest_droppable(msg)) | ||
300 | goto exit; | ||
301 | |||
302 | /* | ||
303 | * construct returned message by copying rejected message header and | ||
304 | * data (or subset), then updating header fields that need adjusting | ||
305 | */ | ||
306 | hdr_sz = msg_hdr_sz(msg); | ||
307 | rmsg_sz = hdr_sz + min_t(u32, data_sz, MAX_REJECT_SIZE); | ||
308 | |||
309 | rbuf = tipc_buf_acquire(rmsg_sz); | ||
310 | if (rbuf == NULL) | ||
311 | goto exit; | ||
312 | |||
313 | rmsg = buf_msg(rbuf); | ||
314 | skb_copy_to_linear_data(rbuf, msg, rmsg_sz); | ||
315 | |||
316 | if (msg_connected(rmsg)) { | ||
317 | imp = msg_importance(rmsg); | ||
318 | if (imp < TIPC_CRITICAL_IMPORTANCE) | ||
319 | msg_set_importance(rmsg, ++imp); | ||
320 | } | ||
321 | msg_set_non_seq(rmsg, 0); | ||
322 | msg_set_size(rmsg, rmsg_sz); | ||
323 | msg_set_errcode(rmsg, err); | ||
324 | msg_set_prevnode(rmsg, tipc_own_addr); | ||
325 | msg_swap_words(rmsg, 4, 5); | ||
326 | if (!msg_short(rmsg)) | ||
327 | msg_swap_words(rmsg, 6, 7); | ||
328 | |||
329 | /* send self-abort message when rejecting on a connected port */ | ||
330 | if (msg_connected(msg)) { | ||
331 | struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg)); | ||
332 | |||
333 | if (p_ptr) { | ||
334 | struct sk_buff *abuf = NULL; | ||
335 | |||
336 | if (p_ptr->connected) | ||
337 | abuf = port_build_self_abort_msg(p_ptr, err); | ||
338 | tipc_port_unlock(p_ptr); | ||
339 | tipc_net_route_msg(abuf); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | /* send returned message & dispose of rejected message */ | ||
344 | src_node = msg_prevnode(msg); | ||
345 | if (in_own_node(src_node)) | ||
346 | tipc_sk_rcv(rbuf); | ||
347 | else | ||
348 | tipc_link_xmit(rbuf, src_node, msg_link_selector(rmsg)); | ||
349 | exit: | ||
350 | kfree_skb(buf); | ||
351 | return data_sz; | ||
352 | } | ||
353 | |||
354 | int tipc_port_iovec_reject(struct tipc_port *p_ptr, struct tipc_msg *hdr, | ||
355 | struct iovec const *msg_sect, unsigned int len, | ||
356 | int err) | ||
357 | { | ||
358 | struct sk_buff *buf; | ||
359 | int res; | ||
360 | |||
361 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
362 | if (!buf) | ||
363 | return res; | ||
364 | |||
365 | return tipc_reject_msg(buf, err); | ||
366 | } | ||
367 | |||
368 | static void port_timeout(unsigned long ref) | 166 | static void port_timeout(unsigned long ref) |
369 | { | 167 | { |
370 | struct tipc_port *p_ptr = tipc_port_lock(ref); | 168 | struct tipc_port *p_ptr = tipc_port_lock(ref); |
371 | struct sk_buff *buf = NULL; | 169 | struct sk_buff *buf = NULL; |
170 | struct tipc_msg *msg = NULL; | ||
372 | 171 | ||
373 | if (!p_ptr) | 172 | if (!p_ptr) |
374 | return; | 173 | return; |
@@ -379,15 +178,16 @@ static void port_timeout(unsigned long ref) | |||
379 | } | 178 | } |
380 | 179 | ||
381 | /* Last probe answered ? */ | 180 | /* Last probe answered ? */ |
382 | if (p_ptr->probing_state == PROBING) { | 181 | if (p_ptr->probing_state == TIPC_CONN_PROBING) { |
383 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); | 182 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); |
384 | } else { | 183 | } else { |
385 | buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); | 184 | buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); |
386 | p_ptr->probing_state = PROBING; | 185 | p_ptr->probing_state = TIPC_CONN_PROBING; |
387 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); | 186 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); |
388 | } | 187 | } |
389 | tipc_port_unlock(p_ptr); | 188 | tipc_port_unlock(p_ptr); |
390 | tipc_net_route_msg(buf); | 189 | msg = buf_msg(buf); |
190 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
391 | } | 191 | } |
392 | 192 | ||
393 | 193 | ||
@@ -395,12 +195,14 @@ static void port_handle_node_down(unsigned long ref) | |||
395 | { | 195 | { |
396 | struct tipc_port *p_ptr = tipc_port_lock(ref); | 196 | struct tipc_port *p_ptr = tipc_port_lock(ref); |
397 | struct sk_buff *buf = NULL; | 197 | struct sk_buff *buf = NULL; |
198 | struct tipc_msg *msg = NULL; | ||
398 | 199 | ||
399 | if (!p_ptr) | 200 | if (!p_ptr) |
400 | return; | 201 | return; |
401 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); | 202 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); |
402 | tipc_port_unlock(p_ptr); | 203 | tipc_port_unlock(p_ptr); |
403 | tipc_net_route_msg(buf); | 204 | msg = buf_msg(buf); |
205 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
404 | } | 206 | } |
405 | 207 | ||
406 | 208 | ||
@@ -412,6 +214,7 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 er | |||
412 | struct tipc_msg *msg = buf_msg(buf); | 214 | struct tipc_msg *msg = buf_msg(buf); |
413 | msg_swap_words(msg, 4, 5); | 215 | msg_swap_words(msg, 4, 5); |
414 | msg_swap_words(msg, 6, 7); | 216 | msg_swap_words(msg, 6, 7); |
217 | buf->next = NULL; | ||
415 | } | 218 | } |
416 | return buf; | 219 | return buf; |
417 | } | 220 | } |
@@ -436,60 +239,11 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er | |||
436 | if (imp < TIPC_CRITICAL_IMPORTANCE) | 239 | if (imp < TIPC_CRITICAL_IMPORTANCE) |
437 | msg_set_importance(msg, ++imp); | 240 | msg_set_importance(msg, ++imp); |
438 | msg_set_errcode(msg, err); | 241 | msg_set_errcode(msg, err); |
242 | buf->next = NULL; | ||
439 | } | 243 | } |
440 | return buf; | 244 | return buf; |
441 | } | 245 | } |
442 | 246 | ||
443 | void tipc_port_proto_rcv(struct sk_buff *buf) | ||
444 | { | ||
445 | struct tipc_msg *msg = buf_msg(buf); | ||
446 | struct tipc_port *p_ptr; | ||
447 | struct sk_buff *r_buf = NULL; | ||
448 | u32 destport = msg_destport(msg); | ||
449 | int wakeable; | ||
450 | |||
451 | /* Validate connection */ | ||
452 | p_ptr = tipc_port_lock(destport); | ||
453 | if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) { | ||
454 | r_buf = tipc_buf_acquire(BASIC_H_SIZE); | ||
455 | if (r_buf) { | ||
456 | msg = buf_msg(r_buf); | ||
457 | tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG, | ||
458 | BASIC_H_SIZE, msg_orignode(msg)); | ||
459 | msg_set_errcode(msg, TIPC_ERR_NO_PORT); | ||
460 | msg_set_origport(msg, destport); | ||
461 | msg_set_destport(msg, msg_origport(msg)); | ||
462 | } | ||
463 | if (p_ptr) | ||
464 | tipc_port_unlock(p_ptr); | ||
465 | goto exit; | ||
466 | } | ||
467 | |||
468 | /* Process protocol message sent by peer */ | ||
469 | switch (msg_type(msg)) { | ||
470 | case CONN_ACK: | ||
471 | wakeable = tipc_port_congested(p_ptr) && p_ptr->congested; | ||
472 | p_ptr->acked += msg_msgcnt(msg); | ||
473 | if (!tipc_port_congested(p_ptr)) { | ||
474 | p_ptr->congested = 0; | ||
475 | if (wakeable) | ||
476 | tipc_port_wakeup(p_ptr); | ||
477 | } | ||
478 | break; | ||
479 | case CONN_PROBE: | ||
480 | r_buf = port_build_proto_msg(p_ptr, CONN_PROBE_REPLY, 0); | ||
481 | break; | ||
482 | default: | ||
483 | /* CONN_PROBE_REPLY or unrecognized - no action required */ | ||
484 | break; | ||
485 | } | ||
486 | p_ptr->probing_state = CONFIRMED; | ||
487 | tipc_port_unlock(p_ptr); | ||
488 | exit: | ||
489 | tipc_net_route_msg(r_buf); | ||
490 | kfree_skb(buf); | ||
491 | } | ||
492 | |||
493 | static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) | 247 | static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) |
494 | { | 248 | { |
495 | struct publication *publ; | 249 | struct publication *publ; |
@@ -581,16 +335,19 @@ void tipc_acknowledge(u32 ref, u32 ack) | |||
581 | { | 335 | { |
582 | struct tipc_port *p_ptr; | 336 | struct tipc_port *p_ptr; |
583 | struct sk_buff *buf = NULL; | 337 | struct sk_buff *buf = NULL; |
338 | struct tipc_msg *msg; | ||
584 | 339 | ||
585 | p_ptr = tipc_port_lock(ref); | 340 | p_ptr = tipc_port_lock(ref); |
586 | if (!p_ptr) | 341 | if (!p_ptr) |
587 | return; | 342 | return; |
588 | if (p_ptr->connected) { | 343 | if (p_ptr->connected) |
589 | p_ptr->conn_unacked -= ack; | ||
590 | buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); | 344 | buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); |
591 | } | 345 | |
592 | tipc_port_unlock(p_ptr); | 346 | tipc_port_unlock(p_ptr); |
593 | tipc_net_route_msg(buf); | 347 | if (!buf) |
348 | return; | ||
349 | msg = buf_msg(buf); | ||
350 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
594 | } | 351 | } |
595 | 352 | ||
596 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, | 353 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, |
@@ -689,7 +446,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
689 | msg_set_hdr_sz(msg, SHORT_H_SIZE); | 446 | msg_set_hdr_sz(msg, SHORT_H_SIZE); |
690 | 447 | ||
691 | p_ptr->probing_interval = PROBING_INTERVAL; | 448 | p_ptr->probing_interval = PROBING_INTERVAL; |
692 | p_ptr->probing_state = CONFIRMED; | 449 | p_ptr->probing_state = TIPC_CONN_OK; |
693 | p_ptr->connected = 1; | 450 | p_ptr->connected = 1; |
694 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); | 451 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); |
695 | 452 | ||
@@ -698,7 +455,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
698 | (net_ev_handler)port_handle_node_down); | 455 | (net_ev_handler)port_handle_node_down); |
699 | res = 0; | 456 | res = 0; |
700 | exit: | 457 | exit: |
701 | p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref); | 458 | p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref); |
702 | return res; | 459 | return res; |
703 | } | 460 | } |
704 | 461 | ||
@@ -741,6 +498,7 @@ int tipc_port_disconnect(u32 ref) | |||
741 | */ | 498 | */ |
742 | int tipc_port_shutdown(u32 ref) | 499 | int tipc_port_shutdown(u32 ref) |
743 | { | 500 | { |
501 | struct tipc_msg *msg; | ||
744 | struct tipc_port *p_ptr; | 502 | struct tipc_port *p_ptr; |
745 | struct sk_buff *buf = NULL; | 503 | struct sk_buff *buf = NULL; |
746 | 504 | ||
@@ -750,149 +508,7 @@ int tipc_port_shutdown(u32 ref) | |||
750 | 508 | ||
751 | buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); | 509 | buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); |
752 | tipc_port_unlock(p_ptr); | 510 | tipc_port_unlock(p_ptr); |
753 | tipc_net_route_msg(buf); | 511 | msg = buf_msg(buf); |
512 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
754 | return tipc_port_disconnect(ref); | 513 | return tipc_port_disconnect(ref); |
755 | } | 514 | } |
756 | |||
757 | /* | ||
758 | * tipc_port_iovec_rcv: Concatenate and deliver sectioned | ||
759 | * message for this node. | ||
760 | */ | ||
761 | static int tipc_port_iovec_rcv(struct tipc_port *sender, | ||
762 | struct iovec const *msg_sect, | ||
763 | unsigned int len) | ||
764 | { | ||
765 | struct sk_buff *buf; | ||
766 | int res; | ||
767 | |||
768 | res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
769 | if (likely(buf)) | ||
770 | tipc_sk_rcv(buf); | ||
771 | return res; | ||
772 | } | ||
773 | |||
774 | /** | ||
775 | * tipc_send - send message sections on connection | ||
776 | */ | ||
777 | int tipc_send(struct tipc_port *p_ptr, | ||
778 | struct iovec const *msg_sect, | ||
779 | unsigned int len) | ||
780 | { | ||
781 | u32 destnode; | ||
782 | int res; | ||
783 | |||
784 | if (!p_ptr->connected) | ||
785 | return -EINVAL; | ||
786 | |||
787 | p_ptr->congested = 1; | ||
788 | if (!tipc_port_congested(p_ptr)) { | ||
789 | destnode = tipc_port_peernode(p_ptr); | ||
790 | if (likely(!in_own_node(destnode))) | ||
791 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
792 | destnode); | ||
793 | else | ||
794 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
795 | |||
796 | if (likely(res != -ELINKCONG)) { | ||
797 | p_ptr->congested = 0; | ||
798 | if (res > 0) | ||
799 | p_ptr->sent++; | ||
800 | return res; | ||
801 | } | ||
802 | } | ||
803 | if (tipc_port_unreliable(p_ptr)) { | ||
804 | p_ptr->congested = 0; | ||
805 | return len; | ||
806 | } | ||
807 | return -ELINKCONG; | ||
808 | } | ||
809 | |||
810 | /** | ||
811 | * tipc_send2name - send message sections to port name | ||
812 | */ | ||
813 | int tipc_send2name(struct tipc_port *p_ptr, | ||
814 | struct tipc_name const *name, | ||
815 | unsigned int domain, | ||
816 | struct iovec const *msg_sect, | ||
817 | unsigned int len) | ||
818 | { | ||
819 | struct tipc_msg *msg; | ||
820 | u32 destnode = domain; | ||
821 | u32 destport; | ||
822 | int res; | ||
823 | |||
824 | if (p_ptr->connected) | ||
825 | return -EINVAL; | ||
826 | |||
827 | msg = &p_ptr->phdr; | ||
828 | msg_set_type(msg, TIPC_NAMED_MSG); | ||
829 | msg_set_hdr_sz(msg, NAMED_H_SIZE); | ||
830 | msg_set_nametype(msg, name->type); | ||
831 | msg_set_nameinst(msg, name->instance); | ||
832 | msg_set_lookup_scope(msg, tipc_addr_scope(domain)); | ||
833 | destport = tipc_nametbl_translate(name->type, name->instance, &destnode); | ||
834 | msg_set_destnode(msg, destnode); | ||
835 | msg_set_destport(msg, destport); | ||
836 | |||
837 | if (likely(destport || destnode)) { | ||
838 | if (likely(in_own_node(destnode))) | ||
839 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
840 | else if (tipc_own_addr) | ||
841 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
842 | destnode); | ||
843 | else | ||
844 | res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, | ||
845 | len, TIPC_ERR_NO_NODE); | ||
846 | if (likely(res != -ELINKCONG)) { | ||
847 | if (res > 0) | ||
848 | p_ptr->sent++; | ||
849 | return res; | ||
850 | } | ||
851 | if (tipc_port_unreliable(p_ptr)) | ||
852 | return len; | ||
853 | |||
854 | return -ELINKCONG; | ||
855 | } | ||
856 | return tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, | ||
857 | TIPC_ERR_NO_NAME); | ||
858 | } | ||
859 | |||
860 | /** | ||
861 | * tipc_send2port - send message sections to port identity | ||
862 | */ | ||
863 | int tipc_send2port(struct tipc_port *p_ptr, | ||
864 | struct tipc_portid const *dest, | ||
865 | struct iovec const *msg_sect, | ||
866 | unsigned int len) | ||
867 | { | ||
868 | struct tipc_msg *msg; | ||
869 | int res; | ||
870 | |||
871 | if (p_ptr->connected) | ||
872 | return -EINVAL; | ||
873 | |||
874 | msg = &p_ptr->phdr; | ||
875 | msg_set_type(msg, TIPC_DIRECT_MSG); | ||
876 | msg_set_lookup_scope(msg, 0); | ||
877 | msg_set_destnode(msg, dest->node); | ||
878 | msg_set_destport(msg, dest->ref); | ||
879 | msg_set_hdr_sz(msg, BASIC_H_SIZE); | ||
880 | |||
881 | if (in_own_node(dest->node)) | ||
882 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
883 | else if (tipc_own_addr) | ||
884 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
885 | dest->node); | ||
886 | else | ||
887 | res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, | ||
888 | TIPC_ERR_NO_NODE); | ||
889 | if (likely(res != -ELINKCONG)) { | ||
890 | if (res > 0) | ||
891 | p_ptr->sent++; | ||
892 | return res; | ||
893 | } | ||
894 | if (tipc_port_unreliable(p_ptr)) | ||
895 | return len; | ||
896 | |||
897 | return -ELINKCONG; | ||
898 | } | ||