1 : /*
2 : * TIPC Linux kernel implementation
3 : * Copyright (c) 2001-2003 Ericsson Research Canada
4 : * Copyright (c) 2003 OSDL, Inc.
5 : *
6 : * This file is based on source code done by Jon Maloy
7 : * (jon.maloy@ericsson.com) for TIPC version 0.96, available from
8 : * http://tipc.sourceforge.net
9 : ***************************************************************************
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; either version 2 of the License, or
13 : * (at your option) any later version.
14 : *
15 : * This program is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU General Public License
21 : * along with this program; if not, write to the Free Software
22 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 : ***************************************************************************
24 : * Alphabetical list of people who have worked on this file:
25 : * - Mark Haverkamp (markh@osdl.org)
26 : * - Mika Kukkonen (mika@osdl.org)
27 : * - Rusty Lynch (rusty@linux.intel.com)
28 : */
29 :
30 : #include <linux/kernel.h>
31 : #include <linux/random.h>
32 : #include <linux/time.h>
33 :
34 : #include "debug.h"
35 : #include "header.h"
36 : #include "msg_buf.h"
37 : #include "media.h"
38 : #include "link.h"
39 : #include "port.h"
40 : #include "net_event.h"
41 : #include "named.h"
42 : #include "name_table.h"
43 : #include "manager.h"
44 : #include "local.h"
45 :
46 : #define STARTING_EVT 856384768
47 :
48 : /* Limits for send queue: */
49 :
50 : #define ROUTED_LIMIT 200u
51 : #define QUEUE_LIMIT 300u
52 :
53 : /* Limit for deferred reception queue: */
54 :
55 : #define DEF_QUEUE_LIMIT 64u
56 :
57 : /* Used as 'nxInNo' when link is reset: */
58 :
59 : #define NON_WORKING 47112255u
60 :
61 : /* Link state definitions: */
62 :
63 : #define WORKING_WORKING 560810u
64 : #define WORKING_UNKNOWN 560811u
65 : #define RESET_UNKNOWN 560812u
66 : #define RESET_RESET 560813u
67 :
68 : /* Link state events: */
69 :
70 : #define TIMEOUT_EVT 560817u
71 :
72 : /* Message piggybacking: */
73 :
74 : /* The following two 'message types' are really just implementation
75 : data conveniently stored in the message header.
76 : They must not be considered a part of the protocol */
77 : #define OPEN_MSG 0
78 : #define CLOSED_MSG 1
79 :
80 : #define BLOCKED 100000u
81 :
82 : #define WINDOW_INCR_FACTOR 16
83 :
84 : static inline uint
85 : buf_cprepend(struct sk_buff *buf, __u8 * data, uint size)
86 34315 : {
87 34315 : if (skb_headroom(buf) < size + 16)
88 : return 0;
89 34315 : UD(buf)->data -= size;
90 34315 : buf->nh.raw = buf->data = UD(buf)->data; /* Please the device layer */
91 68630 : memcpy(buf->data, data, size);
92 : return 1;
93 : }
94 :
95 : void link_releaseQuarantine(Link * this);
96 : void link_addToQuarantine(Link * this, struct sk_buff *buf);
97 : void link_addToDeferredInQueue(Link * this, struct sk_buff *buf);
98 : void link_protocolDataReq(Link * this, uint msgType, uint probe,
99 : uint gap, uint tol, uint prio);
100 : void link_protocolDataInd(Link * this, struct sk_buff *buf);
101 : void link_sendBuf(Link * this, struct sk_buff *buf);
102 : void link_specialMsgInd(Link * this, struct sk_buff *buf);
103 : void link_handleTimeout(Link *);
104 : void link_changeoverDataInd(struct sk_buff *);
105 : void link_send(Link *, tipc_msg_hdr_t * wrapperHeader, struct sk_buff *buf);
106 :
107 : /* Piggybacking: */
108 : void link_bundlerDataInd(Link *, struct sk_buff *);
109 :
110 : /* Segmentation/desegmentation: */
111 : uint link_sendLongMsg(Link * this, const TipcSendMsgArgv *,
112 : tipc_msg_hdr_t * phdr);
113 : void link_sendLongBuf(Link *, struct sk_buff *);
114 : void link_segmDataInd(Link *, struct sk_buff *);
115 :
116 : /* General: */
117 : void link_delete(Link *);
118 : uint link_reset_reset(Link * this);
119 : void link_handleStateEvent(Link * this, uint event);
120 : void link_announceLink(TipcLink * link);
121 : #ifdef CONFIG_TIPC_DBG_BUF
122 : void link_dump(Link *);
123 : #endif
124 : void link_setTolerance(Link * this, uint tolerance);
125 : Link *link_findByName(const char *);
126 :
127 : /* Static data: */
128 : Link *link_pool = 0;
129 :
130 : /* Some useful functions and operators: */
131 : #define align(i) (((i)+3)&~3u)
132 :
133 : #define mod(x) ((x)&0xffff)
134 :
135 : #define between(lo,up,n) \
136 : (\
137 : (uint)((((lo)<(n)) && ((n)<(up)))||(((up)<(lo))&&(((n)>(lo))||((n)<(up)))))\
138 : )
139 :
140 : #define lessEq(l,r) ((uint)(mod((r) - (l)) < 32768))
141 :
142 : #define less(l,r) ((uint)((mod((r)-(l)) < 32768) && ((r) != (l))))
143 :
144 : #define link_selectLocalLink(addr,ref,link) \
145 68630 : {\
146 : struct tipc_node* node;\
147 : if (tipc_local_addr(addr)) {\
148 : node = localnodes[tipc_node_id(addr)];\
149 : link = node->activeLinks[ref&7];\
150 : } else\
151 : link = 0;\
152 : }
153 :
154 : #define link_cancelTimer(this) \
155 : {\
156 : if ((this)->timerRef) os_cancelTimer((this)->timerRef);\
157 : (this)->timerRef = 0;\
158 : }
159 :
160 : #define link_setTimer(this,time) \
161 : {\
162 : if (this->timerRef) {os_cancelTimer(this->timerRef);}\
163 : this->timerRef =\
164 : os_setTimer((TimeoutHandler)link_handleTimeout,this,time);\
165 : }
166 :
167 : /*
168 : * Schedule a port for renewed sending of messages after the link
169 : * congestion has abated. This method is called when somebody
170 : * tries to send a message via this link while it is congested.
171 : */
172 : uint
173 : link_schedulePort(Link * this, uint origport)
174 14 : {
175 14 : Port *port = port_deref(origport);
176 :
177 14 : if (!port || !port->wakeupDispatcher)
178 14 : return EBUSY;
179 : assert(port->nextWaiting == 0);
180 : assert(port->prevWaiting == 0);
181 : assert(this->firstWaiting != port);
182 : assert(this->lastWaiting != port);
183 14 : port->congestedLink = this;
184 14 : if (!this->firstWaiting) {
185 8 : this->firstWaiting = this->lastWaiting = port;
186 8 : port->prevWaiting = port->nextWaiting = 0;
187 : } else { /* Put port last in queue */
188 :
189 6 : port->nextWaiting = 0;
190 6 : port->prevWaiting = this->lastWaiting;
191 6 : this->lastWaiting->nextWaiting = port;
192 6 : this->lastWaiting = port;
193 : }
194 14 : return EBUSY;
195 : }
196 :
197 : void
198 : link_wakeupPorts(Link * this)
199 9 : {
200 9 : Port *port = this->firstWaiting; /* Grab whole queue */
201 9 : Port *last = this->lastWaiting;
202 :
203 9 : if (this->outQueueSize >= this->windowLimit)
204 8 : return;
205 8 : this->firstWaiting = this->lastWaiting = 0;
206 8 : while (port) {
207 14 : Port *next = port->nextWaiting;
208 :
209 14 : port->congestedLink = 0;
210 14 : port->prevWaiting = port->nextWaiting = 0;
211 14 : port->wakeupDispatcher(&port->p);
212 14 : if (this->firstWaiting) { /* New congestion => re-attach queue in front */
213 : assert(0);
214 0 : this->firstWaiting->prevWaiting = last;
215 0 : last->nextWaiting = this->firstWaiting;
216 0 : this->firstWaiting = next;
217 0 : this->firstWaiting->prevWaiting = 0;
218 0 : break;
219 : }
220 14 : port = next;
221 : }
222 : }
223 :
224 : /* Methods to get hold of link state: */
225 : uint
226 : link_working_working(Link * this)
227 1562 : {
228 1562 : return (this->state == WORKING_WORKING);
229 : }
230 :
231 : uint
232 : link_working_unknown(Link * this)
233 0 : {
234 0 : return (this->state == WORKING_UNKNOWN);
235 : }
236 :
237 : uint
238 : link_reset_unknown(Link * this)
239 36029 : {
240 36029 : return (this->state == RESET_UNKNOWN);
241 : }
242 :
243 : uint
244 : link_reset_reset(Link * this)
245 0 : {
246 0 : return (this->state == RESET_RESET);
247 : }
248 :
249 : #define send_queue_consistent(link) \
250 : ({ \
251 : int notgood = ( \
252 : ((link)->firstOut && !(link)->lastOut) || \
253 : ((link)->firstOut && UD((link)->lastOut)->next != 0) || \
254 : ((link)->firstOut && (mod(get_msg_seq_n(buf_msg((link)->lastOut))- \
255 : get_msg_seq_n(buf_msg((link)->firstOut))) != ((link)->outQueueSize-1))) \
256 : ); \
257 : !notgood; \
258 : })
259 :
260 : uint
261 : link_up(Link * this)
262 0 : {
263 0 : return link_working_working(this) | link_working_unknown(this);
264 : }
265 :
266 : void
267 : link_resetStatistics(Link * this)
268 4 : {
269 4 : struct timespec time;
270 :
271 4 : memset(&this->statistics, 0, sizeof (this->statistics));
272 4 : this->statistics.maxPacketSize = this->media->set.max_packet_sz;
273 4 : this->statistics.resetOutPackCount = this->nxOutNo;
274 4 : this->statistics.resetInPackCount = this->nxInNo;
275 4 : time = current_kernel_time();
276 4 : this->statistics.resetTime = time.tv_nsec * 1000;
277 : }
278 :
279 : tipc_net_addr_t
280 : link_findOwner(const char *name)
281 12 : {
282 12 : char *zone_str;
283 12 : char *cluster_str;
284 12 : char *node_str;
285 12 : char nm[72];
286 :
287 12 : if ((!name) || (name[0] != '<'))
288 0 : return 0;
289 12 : memcpy(nm, name, 72);
290 12 : zone_str = nm + 1;
291 12 : cluster_str = strchr(zone_str, '.');
292 12 : *cluster_str++ = 0;
293 12 : node_str = strchr(cluster_str, '.');
294 12 : *node_str++ = 0;
295 12 : *strchr(node_str, ':') = 0;
296 12 : return (tipc_make_addr(simple_strtol(zone_str, (char **) NULL, 10),
297 : simple_strtol(cluster_str, (char **) NULL, 10),
298 : simple_strtol(node_str, (char **) NULL, 10)));
299 : }
300 :
301 : Link *
302 : link_findByName(const char *name)
303 12 : {
304 12 : tipc_net_addr_t addr;
305 12 : char *media_string;
306 12 : char short_media_name[32];
307 12 : char *zone_str;
308 12 : char *cluster_str;
309 12 : char *node_str;
310 12 : struct tipc_media *b = 0;
311 12 : Link *this = 0;
312 12 : char nm[72];
313 :
314 12 : if (tipc_my_addr != link_findOwner(name))
315 0 : return 0;
316 12 : memcpy(nm, name, 72);
317 12 : media_string = strchr(nm, ':') + 1;
318 12 : zone_str = strchr(media_string, '-');
319 12 : *zone_str++ = 0;
320 12 : cluster_str = strchr(zone_str, '.');
321 12 : *cluster_str++ = 0;
322 12 : node_str = strchr(cluster_str, '.');
323 12 : *node_str++ = 0;
324 12 : *strchr(node_str, ':') = 0;
325 12 : sprintf(short_media_name, "%s", media_string);
326 12 : b = media_find_by_name(short_media_name);
327 12 : if (!b)
328 0 : return 0;
329 12 : addr = tipc_make_addr(simple_strtol(zone_str, (char **) NULL, 10),
330 : simple_strtol(cluster_str, (char **) NULL, 10),
331 : simple_strtol(node_str, (char **) NULL, 10));
332 :
333 12 : this = link_find(addr, b->id);
334 12 : return this;
335 : }
336 :
337 : Link *
338 : link_new(struct tipc_media * b, const tipc_net_addr_t peer,
339 : struct tipc_media_addr * media_addr)
340 4 : {
341 4 : Link *this;
342 4 : uint random;
343 4 : struct tipc_zone *z;
344 :
345 5 : mem_cnew(this, link_pool, 16000);
346 4 : this->rep.media = (struct tipc_media *) b;
347 4 : this->rep.addr = peer;
348 4 : this->priority = b->set.priority;
349 4 : this->windowLimit = b->set.packet_window_sz;
350 4 : this->media = (struct tipc_media *) b;
351 4 : this->nextOnBearer = this->media->links;
352 4 : this->media->links = this;
353 4 : this->checkpoint = NOT_A_SEQNO;
354 4 : this->state = RESET_UNKNOWN;
355 4 : this->remoteBearerId = 17;
356 4 : this->changingOver = 0;
357 4 : this->nxOutNo = 1;
358 4 : this->nxInNo = NON_WORKING;
359 4 : link_resetStatistics(this);
360 4 : memcpy(&this->rep.mediaAddr, media_addr, sizeof (*media_addr));
361 4 : this->statistics.maxPacketSize = this->media->set.max_packet_sz;
362 4 : link_setTolerance(this, b->set.tolerance);
363 : dbg("LINK: tolerance = %u,contIntv = %u, abortLimit = %u\n",
364 : this->tolerance, this->continuityInterval, this->abortLimit);
365 4 : link_segmReset(this);
366 :
367 : /* Attach to corresponding node : */
368 :
369 4 : z = network.zones[tipc_zone_id(this->rep.addr)];
370 :
371 4 : if (z && z->clusters[1])
372 3 : this->owner =
373 : z->clusters[1]->nodes[tipc_node_id(this->rep.addr)];
374 : else
375 1 : this->owner = 0;
376 : dbg(" Link: Owner = %p, creating node\n", this->owner);
377 4 : if (!this->owner)
378 2 : this->owner = tipc_node_new(this->rep.addr);
379 4 : if (!tipc_node_attachlink(this->owner, this)) {
380 : warn("Link on media %s to <%u.%u.%u> already registered\n",
381 : (this->media)->name,
382 : tipc_zone_id(this->rep.addr),
383 : tipc_cluster_id(this->rep.addr),
384 0 : tipc_node_id(this->rep.addr));
385 0 : return 0;
386 : }
387 :
388 4 : sprintf(this->rep.name, "<%u.%u.%u:%s-%u.%u.%u:>",
389 : tipc_zone_id(tipc_my_addr), tipc_cluster_id(tipc_my_addr),
390 : tipc_node_id(tipc_my_addr),
391 : this->media->name, tipc_zone_id(peer),
392 : tipc_cluster_id(peer), tipc_node_id(peer));
393 :
394 : /* Prepare a reusable buffer for protocol messages */
395 : {
396 4 : tipc_msg_hdr_t *msg;
397 :
398 4 : this->protocolBuf = buf_acquire(INTERNAL_HDR_SIZE + IFNAMSIZ);
399 : dbg("link_create: got buffer %p\n", this->protocolBuf);
400 4 : msg = buf_msg(this->protocolBuf);
401 4 : memset(msg, 0, INTERNAL_HDR_SIZE + IFNAMSIZ);
402 8 : set_msg_version(msg, MSG_VERSION_1);
403 8 : set_msg_user(msg, LINK_PROTOCOL);
404 8 : set_hdr_size(msg, INTERNAL_HDR_SIZE);
405 8 : set_msg_size(msg, INTERNAL_HDR_SIZE + IFNAMSIZ);
406 4 : set_prev_node(msg, tipc_my_addr);
407 8 : set_media_id(msg, this->media->id);
408 4 : get_random_bytes(&random, sizeof (random));
409 : set_msg_session(msg,
410 8 : (random & 0xffff) ? (random & 0xffff) : 17779);
411 8 : strcpy((char *) msg_data_start(msg), this->media->name);
412 4 : UD(this->protocolBuf)->next = 0;
413 : }
414 4 : return this;
415 : }
416 :
417 : void
418 : link_delete(Link * this)
419 0 : {
420 0 : Link **crs;
421 :
422 0 : if (!this)
423 0 : return;
424 0 : link_reset(this);
425 0 : this->owner->links[this->media->id] = 0;
426 0 : link_stop(this);
427 0 : for (crs = &this->media->links; (*crs); crs = &((*crs)->next)) {
428 0 : if ((*crs) == this) {
429 0 : *crs = this->next;
430 0 : break;
431 : }
432 : }
433 0 : memset(this, 0, sizeof (Link));
434 0 : this->next = link_pool;
435 0 : link_pool = this;
436 : }
437 :
438 : void
439 : link_setupTimer(Link * this)
440 0 : {
441 0 : if (!this)
442 0 : return;
443 0 : if (link_reset_unknown(this)) {
444 0 : tipc_net_addr_t addr = this->rep.addr;
445 :
446 0 : link_delete(this);
447 0 : tipc_manager_link_setup(addr & 0xff000000);
448 : }
449 : }
450 :
451 : void
452 : link_start(Link * this)
453 4 : {
454 4 : link_handleStateEvent(this, STARTING_EVT);
455 4 : if (tipc_zone_id(this->rep.addr) != tipc_my_zone.id) {
456 0 : os_setTimer((TimeoutHandler) link_setupTimer, (void *) this,
457 : 15000);
458 : }
459 : }
460 :
461 : const char *
462 : link_state(Link * this)
463 8 : {
464 8 : if (tipc_node_active(this->owner, this))
465 8 : return "ACTIVE";
466 0 : else if (link_working_working(this) || link_working_unknown(this)) {
467 0 : return "STANDBY";
468 : } else
469 0 : return "DEFUNCT";
470 : }
471 :
472 : void
473 : link_releaseQuarantine(Link * this)
474 1597 : {
475 1597 : struct sk_buff *buf = this->quarantineFirst;
476 :
477 1597 : while (buf) {
478 43 : struct sk_buff *next = UD(buf)->next;
479 :
480 43 : if (skb_shared(buf))
481 37 : break;
482 37 : buf_discard(buf);
483 37 : buf = next;
484 : }
485 1597 : this->quarantineFirst = buf;
486 : }
487 :
488 : void
489 : link_addToQuarantine(Link * this, struct sk_buff *buf)
490 37 : {
491 37 : link_releaseQuarantine(this); /* Keep it as short as possible */
492 37 : if (!skb_shared(buf)) {
493 0 : buf_discard(buf);
494 37 : return;
495 : }
496 37 : UD(buf)->next = 0;
497 37 : if (!this->quarantineFirst) {
498 31 : this->quarantineFirst = this->quarantineLast = buf;
499 : } else {
500 6 : UD(this->quarantineLast)->next = buf;
501 6 : this->quarantineLast = buf;
502 : }
503 : }
504 :
505 : void
506 : link_releaseOutQueue(Link * this)
507 0 : {
508 0 : struct sk_buff *buf = this->firstOut;
509 :
510 0 : while (buf) {
511 0 : struct sk_buff *next = UD(buf)->next;
512 :
513 0 : if (skb_shared(buf))
514 0 : link_addToQuarantine(this, buf);
515 : else
516 0 : buf_discard(buf);
517 0 : buf = next;
518 : }
519 0 : this->firstOut = 0;
520 : }
521 :
522 : void
523 : link_reset(Link * this)
524 0 : {
525 0 : struct sk_buff *iter;
526 :
527 0 : uint prevState = this->state;
528 0 : uint checkpoint = this->nxInNo;
529 0 : tipc_msg_hdr_t *pmsg = buf_msg(this->protocolBuf);
530 0 : uint newsession = (get_msg_session(pmsg) + 1) & 0xffff;
531 :
532 0 : set_msg_session(pmsg, newsession ? newsession : 17865); /* Compatiblility: avoid 0 */
533 0 : this->remoteSession = 0; /* Link is down, accept any session */
534 0 : this->nxInNo = NON_WORKING;
535 0 : this->state = RESET_UNKNOWN;
536 :
537 : dbg_msg("Resetting Link\n");;
538 0 : if ((prevState == RESET_UNKNOWN) || (prevState == RESET_RESET)) {
539 0 : return;
540 : }
541 :
542 0 : tipc_node_lostlink(this->owner, this);
543 : dbg_msg("Reset link to %x on %s ...\n",
544 : this->rep.addr, (this->media)->name);
545 0 : if (tipc_node_activelinks(this->owner)) {
546 0 : this->resetCheckpoint = checkpoint;
547 0 : this->expectedMsgCount = BLOCKED;
548 : }
549 :
550 : /* Clean up all queues: */
551 :
552 0 : link_releaseOutQueue(this);
553 0 : link_releaseQuarantine(this);
554 0 : this->protocolMsgQueue = 0;
555 0 : iter = this->oldestDeferredIn;
556 0 : while (iter) {
557 0 : struct sk_buff *next = UD(iter)->next;
558 :
559 0 : buf_discard(iter);
560 0 : iter = next;
561 : }
562 0 : if (this->firstWaiting)
563 0 : link_wakeupPorts(this);
564 0 : this->retransmitQueueHead = 0;
565 0 : this->retransmitQueueLength = 0;
566 0 : this->lastOut = 0;
567 0 : this->firstOut = 0;
568 0 : this->nextOut = 0;
569 0 : this->unackedWindow = 0;
570 0 : this->outQueueSize = 0;
571 0 : this->checkpoint = NOT_A_SEQNO;
572 0 : this->nxOutNo = 1;
573 0 : this->deferredInQueueSize = 0;
574 0 : this->oldestDeferredIn = 0;
575 0 : this->newestDeferredIn = 0;
576 0 : this->stateMsgCount = 0;
577 0 : this->nonSequenceCount = 0;
578 0 : this->delayedCount = 0;
579 0 : link_resetStatistics(this);
580 : }
581 :
582 : void
583 : link_activate(Link * this)
584 4 : {
585 4 : this->nxInNo = 1;
586 4 : tipc_node_establishedlink(this->owner, this);
587 : }
588 :
589 : /*
590 : * Schedule link for 'pushing' of messages when a continue
591 : * interrupt arrives
592 : */
593 : #define link_addToOutQueue(this,buf) \
594 : {\
595 : UD(buf)->next = 0;\
596 : if ((this)->firstOut)\
597 : {\
598 : UD((this)->lastOut)->next = buf;\
599 : (this)->lastOut = buf;\
600 : }\
601 : else (this)->firstOut = (this)->lastOut = buf;\
602 : if(get_msg_user(buf_msg(buf))<4){dbg_msg("Sending: ");}\
603 : (this)->outQueueSize++;\
604 : }
605 :
606 : /*
607 : // The following description concerns the link FSM.
608 : //
609 : // The member 'nxInNo' is correlated to link state, because
610 : // this makes the sequence number check at each message reception an
611 : // implicit test that connection state is active.
612 : // If nxInNo < 65536 we know that link is either in state
613 : // WORKING_WORKING or WORKING_UNKNOWN, both states legal for reception,
614 : // and no further testing is necessary.
615 : //
616 : // From the wiewpoint of one party a link runs through the
617 : // following FSM:
618 : //
619 : // +--------------+ +---------------+
620 : // | WORKING_ | <---Checkpoint----- | WORKING_ |
621 : // | UNKNOWN | | WORKING |
622 : // | | --TRAFFIC/ACTIVATE--> | |
623 : // | | | |
624 : // +--------------+\ /----ACTIVATE---->+---------------+
625 : // | \ / | A
626 : // |LOST PROBES \/ | RESET | TRAFFIC/
627 : // | /\ | | ACTIVATE
628 : // V / \ V |
629 : // +--------------+/ \----RESET------> +---------------+
630 : // | | | |
631 : // | RESET_ | | RESET_ |
632 : // | UNKNOWN | ------RESET---------> | RESET |
633 : // | | | |
634 : // +--------------+ +---------------+
635 : //
636 : //
637 : // WORKING_WORKING: Own link object working. Peer link object known
638 : // to be working, i.e. both can send and receive
639 : // traffic messages. A timeout checks periodically if
640 : // anything has been received from peer during
641 : // the corresponding timeout interval. If not state
642 : // transfers to WORKING_UNKNOWN.
643 : //
644 : // WORKING_UNKNOWN: Own link object active. Peer link object in
645 : // unknown state. PROBE messages are sent periodically
646 : // to get a response from peer. If a calculated number
647 : // of probes (tolerance/(continuityInterval/4)) remain
648 : // unresponded state transfers to RESET_UNKNOWN.
649 : // Own link object is reset,link is considered lost.
650 : // If a traffic message (inclusive probe/probe reply)
651 : // is received state transfers back to WORKING_WORKING.
652 : //
653 : // RESET_UNKNOWN: Own link object reset, i.e. queues are emptied,
654 : // sequence numbers reset etc. Peer link object in
655 : // unknown state. RESET messages are sent periodically
656 : // to reset peer. If peer is rebooting or has reset
657 : // because of the link disturbance it will sooner
658 : // or later reach state RESET_UNKNOWN and start sending
659 : // RESETS periodically. At least one of the peers, but
660 : // most often both will then receive a RESET and transfer
661 : // state to RESET_RESET.
662 : // If however the peer is still active, i.e. it has not yet
663 : // detected the disturbance which caused this party to
664 : // reset the link, it will sooner or later receive a RESET
665 : // from this party, and transfer to RESET_RESET.
666 : // If an ACTIVATE message is received we know that
667 : // peer is in state RESET_RESET and can move directly
668 : // on to state WORKING_WORKING.
669 : // Traffic messages (incl probes) are ignored in this
670 : // state.
671 : //
672 : // RESET_RESET: Own link object reset, and peer is known to be reset.
673 : // This is because the only way to reach this state is
674 : // through receiving a RESET from peer.
675 : // Link object is periodically sending ACTIVATE, which
676 : // will eventually cause peer to transfer state to
677 : // WORKING_WORKING. Own party will also transfer to
678 : // WORKING_WORKING as soon as an ACTIVATE or traffic
679 : // message is received.
680 : //
681 : // The reason for this rather complicated state machine is that a
682 : // node might sometimes restart too fast for a peer node
683 : // to detect it. In that case we must make sure that the peer link
684 : // object is reset before starting using the link.
685 : */
686 :
687 : /*
688 : * Link::handleStateEvent handles transitions in the link FSM
689 : * according to incoming state events.
690 : */
691 : void
692 : link_handleStateEvent(Link * this, uint event)
693 36261 : {
694 36261 : if (!this->started && (event != STARTING_EVT))
695 36261 : return; /* Not yet. */
696 36261 : if (this->expectedMsgCount) {
697 0 : if (event == TIMEOUT_EVT) {
698 0 : link_setTimer(this, this->continuityInterval);
699 : }
700 0 : return; /* Changeover going on */
701 : }
702 : dbg_msg("LINK %s->%x STATE_EV(", this->media->name, this->rep.addr);
703 36261 : switch (this->state) {
704 : case WORKING_WORKING:
705 : {
706 : dbg_msg("WW/\n");
707 36031 : switch (event) {
708 : case TRAFFIC_MSG_EVT:
709 : case ACTIVATE_MSG:
710 : {
711 : dbg_msg("Traffic/ACT)\n");
712 222 : break;
713 : }
714 : case TIMEOUT_EVT:
715 : {
716 : dbg_msg("TIM)\n");
717 222 : if (this->nxInNo != this->checkpoint) {
718 0 : this->checkpoint = this->nxInNo;
719 : link_setTimer(this,
720 : this->
721 0 : continuityInterval);
722 0 : return;
723 : }
724 222 : this->state = WORKING_UNKNOWN;
725 222 : link_protocolDataReq(this, STATE_MSG,
726 : 1, 0, 0, 0);
727 222 : this->stateMsgCount = 1;
728 : link_setTimer(this,
729 : this->continuityInterval /
730 222 : 4);
731 222 : break;
732 : }
733 : case RESET_MSG:
734 : {
735 : dbg_msg("RES)\n");
736 0 : link_reset(this);
737 0 : this->state = RESET_RESET;
738 0 : link_protocolDataReq(this, ACTIVATE_MSG,
739 : 0, 0, 0, 0);
740 : dbg_msg("Sent ACTIVATE\n");
741 0 : this->stateMsgCount = 1;
742 : link_setTimer(this,
743 0 : this->continuityInterval);
744 0 : break;
745 : }
746 : default:
747 : {
748 : }
749 : }
750 222 : break;
751 : }
752 : case WORKING_UNKNOWN:
753 : {
754 : dbg_msg("WU/\n");
755 222 : switch (event) {
756 : case TRAFFIC_MSG_EVT:
757 : case ACTIVATE_MSG:
758 : {
759 : dbg_msg("TR/ACT)\n");
760 222 : this->state = WORKING_WORKING;
761 222 : this->stateMsgCount = 0;
762 : link_setTimer(this,
763 222 : this->continuityInterval);
764 222 : break;
765 : }
766 : case RESET_MSG:
767 : {
768 : dbg_msg("RES)\n");
769 0 : link_reset(this);
770 0 : this->state = RESET_RESET;
771 0 : link_protocolDataReq(this, ACTIVATE_MSG,
772 : 0, 0, 0, 0);
773 0 : this->stateMsgCount = 1;
774 : link_setTimer(this,
775 0 : this->continuityInterval);
776 0 : break;
777 : }
778 : case TIMEOUT_EVT:
779 : {
780 : dbg_msg("TIM:\n");
781 0 : if (this->nxInNo != this->checkpoint) { /* Situation is resolved */
782 : dbg_msg("Resolved)\n");
783 0 : this->state = WORKING_WORKING;
784 0 : this->stateMsgCount = 0;
785 : link_setTimer(this,
786 : this->
787 0 : continuityInterval);
788 0 : return;
789 0 : } else if (this->stateMsgCount <
790 : this->abortLimit)
791 : /* Continue probing */
792 : {
793 : dbg_msg
794 : ("Probing %u/%u,timer = %u ms)\n",
795 : this->stateMsgCount,
796 : this->abortLimit,
797 : this->continuityInterval /
798 : 4);
799 0 : link_protocolDataReq(this,
800 : STATE_MSG,
801 : 1, 0, 0,
802 : 0);
803 0 : this->stateMsgCount++;
804 : link_setTimer(this,
805 : this->
806 : continuityInterval
807 0 : / 4);
808 : } else { /* Abort connection */
809 :
810 0 : this->stateMsgCount = 1;
811 0 : link_reset(this);
812 0 : this->state = RESET_UNKNOWN;
813 0 : link_protocolDataReq(this,
814 : RESET_MSG,
815 : 0, 0,
816 : 0, 0);
817 : link_setTimer(this,
818 : this->
819 0 : continuityInterval);
820 0 : return;
821 : }
822 8 : break;
823 : }
824 : default:
825 : {
826 : }
827 : }
828 8 : break;
829 : }
830 : case RESET_UNKNOWN:
831 : {
832 : dbg_msg("RU/\n");
833 8 : link_releaseQuarantine(this);
834 8 : switch (event) {
835 : case TRAFFIC_MSG_EVT:
836 : {
837 : dbg_msg("TRAFFIC)\n");
838 4 : return;
839 : }
840 : case ACTIVATE_MSG:
841 : {
842 : dbg_msg("ACT)\n");
843 4 : this->state = WORKING_WORKING;
844 4 : this->stateMsgCount = 0;
845 4 : link_activate(this);
846 4 : link_protocolDataReq(this, STATE_MSG, 1, 0, 0, 0); /* Will activate peer */
847 : link_setTimer(this,
848 4 : this->continuityInterval);
849 4 : break;
850 : }
851 : case RESET_MSG:
852 : {
853 : dbg_msg("RES)\n");
854 0 : this->state = RESET_RESET;
855 0 : link_protocolDataReq(this, ACTIVATE_MSG,
856 : 1, 0, 0, 0);
857 0 : this->stateMsgCount = 1;
858 : link_setTimer(this,
859 0 : this->continuityInterval);
860 0 : break;
861 : }
862 : case STARTING_EVT:
863 : {
864 : dbg_msg("START_EVT to %x \n",
865 : this->rep.addr);
866 4 : this->started = 1;
867 : }
868 : case TIMEOUT_EVT:
869 : {
870 : dbg_msg("START/TIM)\n");
871 :
872 4 : link_protocolDataReq(this, RESET_MSG,
873 : 0, 0, 0, 0);
874 :
875 4 : if (++(this->stateMsgCount) <= 4) { /* Use higher rate in the beginning */
876 : link_setTimer(this,
877 : this->
878 4 : continuityInterval);
879 0 : } else if (tipc_node_activelinks(this->owner)) { /* Bearer problem */
880 : link_setTimer(this,
881 : this->
882 : continuityInterval
883 0 : * 10);
884 : } else { /* Peer probably restarting. Keep low rate. */
885 0 : struct tipc_link_addr addr;
886 :
887 0 : addr.media = this->media;
888 0 : addr.orig = tipc_my_addr;
889 0 : addr.dest = this->rep.addr;
890 : memcpy(&addr.dest_media,
891 : (struct tipc_media_addr
892 : *)
893 : &this->rep.mediaAddr,
894 : sizeof (struct
895 0 : tipc_media_addr));
896 0 : media_request_link(&addr);
897 : link_setTimer(this,
898 : this->
899 : continuityInterval
900 0 : * 60);
901 : }
902 0 : break;
903 : }
904 : default:
905 : {
906 0 : warn("IPC: Unknown link event %u in RESET_UNKNOWN state)\n", event);
907 : }
908 : }
909 0 : break;
910 : }
911 : case RESET_RESET:
912 : {
913 : dbg_msg("RR, \n");
914 0 : link_releaseQuarantine(this);
915 0 : switch (event) {
916 : case TRAFFIC_MSG_EVT:
917 : case ACTIVATE_MSG:
918 : {
919 : dbg_msg("TR/ACT)\n");
920 0 : this->state = WORKING_WORKING;
921 0 : this->stateMsgCount = 0;
922 0 : link_activate(this);
923 0 : link_protocolDataReq(this, STATE_MSG, 1, 0, 0, 0); /* Will activate peer */
924 : link_setTimer(this,
925 0 : this->continuityInterval);
926 0 : break;
927 : }
928 : case RESET_MSG:
929 : {
930 : dbg_msg("RES)\n");
931 0 : break;
932 : }
933 : case TIMEOUT_EVT:
934 : {
935 : dbg_msg("TIM)\n");
936 0 : link_protocolDataReq(this, ACTIVATE_MSG,
937 : 0, 0, 0, 0);
938 0 : this->stateMsgCount++;
939 0 : if (this->stateMsgCount <= 4) { /* Keep a higher rate in the beginning */
940 : link_setTimer(this,
941 : this->
942 0 : continuityInterval);
943 : } else
944 : link_setTimer(this,
945 : this->
946 : continuityInterval
947 0 : * 5);
948 : break;
949 : }
950 : default:
951 : {
952 : }
953 : }
954 36261 : break;
955 : }
956 : default:
957 : {
958 : assert(!"IPC: Unknown link state \n");
959 : }
960 : }
961 : }
962 :
963 : /*
964 :
965 : ///////////////////////////////////////////////////////////////////
966 : //
967 : //
968 : // The link send queue is subdivided into logical areas with
969 : // certain access restrictions, depending on message type and
970 : // characteristics. Only the 'sent messages' area is non-empty
971 : // under normal conditions.
972 : //
973 : // 'User messages', i.e. messages sent directly from a process
974 : // can easily be queued up in case of link congestion simply
975 : // by having a repetitive delay of the sending process, thus
976 : // in fact using the timer and scheduling queues as an extension
977 : // to the link send queue.
978 : //
979 : // In order to avoid starvation we want to treat long user
980 : // messages (i.e. messages needing segmentation) exactly the
981 : // same way as ordinary ones with respect to congestion.
982 : // Therefore subsequent segments of a long message are allowed to
983 : // 'spill over' the window limit border and be queued there until
984 : // the queue has decreased enough for permitting transmission.
985 : // This is the idea behind the 'deferred segment queue' area.
986 : //
987 : // 'Routed' and NAS messages are called in supervisor mode and can
988 : // not be delayed in the same way as user messages. Furthermore,
989 : // NAS messages must never be rejected or thrown away, as this
990 : // would make the port name translation tables inconsistent.
991 : // Instead we allow the send queue to grow even beyond the
992 : // deferred segment queue limit, but reserve these areas for
993 : // these two kinds of messages.
994 : // Of course these areas will be used only in extreme situations,
995 : // helping the link to overcome transient congestion.
996 : //
997 : //
998 : //
999 : // tipc_sendMsg: link_sendBuf:
1000 : // | |
1001 : // | +-------------------------+oldest |
1002 : // | | Retransmitting msg queue| |
1003 : // | | | |
1004 : // | | Available for: | |
1005 : // | | All message types | |
1006 : // | | ^ | |
1007 : // | +----------------|---|----+retransmits |
1008 : // | send ? | v | |
1009 : // |----------->| Sent msgs queue | send ? |
1010 : // | | |<----------------|
1011 : // | | Available for: | |
1012 : // | | All message types | |
1013 : // | | ^ | |
1014 : // | +--------------------|----+nextOut |
1015 : // | scedule ? | | |
1016 : // |----------->| Scheduled msg queue | schedule ? |
1017 : // | | |<----------------|
1018 : // | | Available for: | |
1019 : // | | All message types | |
1020 : // | | ^ | |
1021 : // | +--------------------|----+WINDOW_LIMIT |
1022 : // | segment ? | | |
1023 : // |----------->| Deferred segment queue | |
1024 : // | | | routed | NAS ? |
1025 : // v | Available for: |<----------------|
1026 : // +---------+ | User data segments, | |
1027 : // | return | | Routed messages | |
1028 : // | conges- | | NAS messages | |
1029 : // | tion | | | |
1030 : // +---------+ | ^ | |
1031 : // +--------------------|----+WINDOW_LIMIT+ |
1032 : // | |MAX_SEGMENTS |
1033 : // | Deferred routed queue | |
1034 : // | | |
1035 : // | Available for: | routed | NAS ? |
1036 : // | Routed messages |<----------------|
1037 : // | NAS messages | |
1038 : // | | |
1039 : // | ^ | |
1040 : // +--------------------|----+ROUTED_LIMIT |
1041 : // | | |
1042 : // | Deferred NAS msg queue | |
1043 : // | | NAS message? |
1044 : // | Available for: |<----------------|
1045 : // | NAS messages | v
1046 : // | | Reset link
1047 : // | |
1048 : // +-------------------------+QUEUE_LIMIT
1049 : //
1050 : //
1051 : */
1052 :
1053 : /*
1054 : * tipc_sendMsg: Entry for messages where the destination
1055 : * node is known and the pre-built header is complete,
1056 : * except for total message length.
1057 : */
1058 : uint
1059 : tipc_sendMsg(TipcSendMsgArgv * argv)
1060 0 : {
1061 0 : Link *this;
1062 0 : uint scnt;
1063 0 : uint hdrlen;
1064 0 : const TipcMsgSection *sseq;
1065 0 : uint size;
1066 0 : char *data;
1067 0 : uint res;
1068 0 : uint i;
1069 0 : Port *port;
1070 0 : tipc_msg_hdr_t *phdr;
1071 0 : uint origport;
1072 0 : tipc_net_addr_t destnode;
1073 0 : struct sk_buff *buf;
1074 0 : tipc_msg_hdr_t *msg;
1075 :
1076 : /* Get sending port and pre-built header: */
1077 0 : origport = argv->origport;
1078 0 : port = port_deref(origport);
1079 0 : if (!port)
1080 0 : return tipc_userError(tipc_invalid_args);
1081 0 : phdr = port_phdr(port);
1082 :
1083 : /* Determine destination */
1084 0 : destnode = get_dest_node(phdr);
1085 :
1086 0 : if (destnode == tipc_my_addr)
1087 0 : return port_sendMsg(port, argv);
1088 :
1089 : /* Calculate some basic values : */
1090 0 : scnt = argv->sectionCount;
1091 0 : if (scnt > 128)
1092 0 : return tipc_userError(tipc_oversized_message);
1093 0 : sseq = argv->sectionSeq;
1094 0 : size = hdrlen = get_hdr_size(phdr);
1095 0 : for (i = 0; i < scnt; i++) {
1096 0 : size += sseq[i].size;
1097 : }
1098 0 : set_msg_size(phdr, size);
1099 0 : if (is_local_delivery(phdr) && is_direct_connect(phdr)) {
1100 0 : set_conn_seq_n(phdr, (get_conn_seq_n(phdr) + 1));
1101 : }
1102 :
1103 : /* Get link reference. First,assume that call is intra cluster: */
1104 0 : link_selectLocalLink(destnode, origport, this);
1105 0 : if (!this) {
1106 0 : if (is_local_delivery(phdr))
1107 0 : this = link_select(destnode, origport);
1108 0 : if (!this)
1109 0 : return port_rejectReq(argv, phdr, tipc_no_remote_node);
1110 : }
1111 :
1112 0 : if (size > this->media->set.max_packet_sz) {
1113 0 : if (size > TIPC_MAX_DATA_SIZE + LONG_HDR_SIZE) {
1114 0 : return tipc_userError(tipc_oversized_message);
1115 : }
1116 : /* Build and send long message. Allow window overflow once */
1117 0 : return link_sendLongMsg(this, argv, phdr);
1118 : }
1119 :
1120 0 : buf = buf_acquire(size);
1121 0 : if (!buf) {
1122 0 : return link_schedulePort(this, argv->origport);
1123 : }
1124 : /* Build message: */
1125 :
1126 0 : msg = buf_msg(buf);
1127 0 : memcpy((char *) msg, phdr, hdrlen);
1128 0 : data = ((char *) msg) + hdrlen;
1129 0 : res = 1;
1130 0 : for (i = 0; i < scnt; i++) {
1131 0 : res =
1132 : res & ((uint) memcpy(data, sseq[i].data, sseq[i].size) | 1);
1133 0 : data += sseq[i].size;
1134 : }
1135 0 : if (res) {
1136 : /* Check conditions for sending: */
1137 :
1138 0 : if (this->outQueueSize >= this->windowLimit) {
1139 0 : uint winlimit =
1140 : this->windowLimit +
1141 0 : (WINDOW_INCR_FACTOR * get_msg_user(msg));
1142 :
1143 0 : if (this->outQueueSize >= winlimit) {
1144 : /* Link congestion. Resolve possible deadlock */
1145 0 : if (!(++this->delayedCount % 16)) {
1146 0 : this->statistics.sentDeadlockAcks++;
1147 0 : link_protocolDataReq(this, STATE_MSG,
1148 : 1, 0, 0, 0);
1149 : }
1150 0 : this->statistics.windowOverflows++;
1151 0 : if (is_local_delivery(phdr) && is_direct_connect(phdr)) { /* Restore */
1152 : set_conn_seq_n(phdr,
1153 : (get_conn_seq_n(phdr) -
1154 0 : 1));
1155 : }
1156 0 : buf_discard(buf);
1157 : dbg("LINK: Returning EBUSY: Queue is %u,Window is %u \n", this->outQueueSize, winlimit);
1158 0 : return link_schedulePort(this, argv->origport);
1159 : }
1160 0 : link_sendBuf(this, buf); /* Will piggyback or queue buffer */
1161 0 : return 0;
1162 : }
1163 :
1164 0 : if (this->media->busy_links) {
1165 0 : link_sendBuf(this, buf); /* Will piggyback or queue buffer */
1166 0 : return 0;
1167 : }
1168 :
1169 : /* ==== Message can be sent ===== */
1170 :
1171 : set_hdr_w(msg, 1,
1172 : ((mod(this->nxInNo - 1) << 16) |
1173 0 : mod(this->nxOutNo++)));
1174 0 : link_addToOutQueue(this, buf);
1175 0 : if (!this->media->api->send_msg(this->media, &this->rep, buf)) {
1176 0 : this->unackedWindow = 0;
1177 : } else {
1178 : dbg_msg(">BCONG>");
1179 0 : if (!(this->next))
1180 0 : media_schedule(this->media, this);
1181 0 : this->nextOut = buf;
1182 : }
1183 0 : return 0;
1184 : } else {
1185 0 : buf_discard(buf);
1186 0 : return tipc_userError(tipc_invalid_message);
1187 : }
1188 :
1189 : assert(!"TIPC:Send queue condition check algorithm wrong\n");
1190 : }
1191 :
1192 : /*
1193 : * link_sendBuf is called from inside TIPC when messages are
1194 : * routed or when message source is internal
1195 : */
1196 : void
1197 : link_sendBuf(Link * this, struct sk_buff *buf)
1198 445572 : {
1199 445572 : tipc_msg_hdr_t *msg = buf_msg(buf);
1200 445572 : uint size = get_msg_size(msg);
1201 :
1202 : /* Find appropriate queue limits: */
1203 :
1204 1302432 : uint importance = get_real_importance(msg);
1205 445572 : uint routedlimit = ROUTED_LIMIT * (importance + 1);
1206 445572 : uint queuelimit = QUEUE_LIMIT * (importance + 1);
1207 :
1208 445572 : if (this->changingOver) {
1209 0 : routedlimit *= 2;
1210 0 : queuelimit *= 2;
1211 : }
1212 :
1213 : /* Is message short enough to fit in one buffer ? */
1214 :
1215 445572 : if (size > this->media->set.max_packet_sz) {
1216 34268 : if ((get_msg_user(msg) != CHANGEOVER_PROTOCOL) ||
1217 : (size >
1218 : this->media->set.max_packet_sz + INTERNAL_HDR_SIZE)) {
1219 34268 : link_sendLongBuf(this, buf); /* Will call back recursively */
1220 34268 : return;
1221 : }
1222 : }
1223 411304 : msg = buf_msg(buf);
1224 411304 : set_prev_node(msg, tipc_my_addr); /* In case of incoming routed message */
1225 411304 : if (this->outQueueSize > this->statistics.maxQueueSize) {
1226 114 : this->statistics.maxQueueSize = this->outQueueSize;
1227 : }
1228 : /* Serious link congestion ? */
1229 :
1230 411304 : if (this->outQueueSize >= (QUEUE_LIMIT * (tipc_non_rejectable + 1))) { /* On est fichu */
1231 0 : err("Resetting link through %s to <%u.%u.%u>, send queue is full", (this->media)->name, tipc_zone_id(this->rep.addr), tipc_cluster_id(this->rep.addr), tipc_node_id(this->rep.addr));
1232 0 : link_reset(this);
1233 0 : return;
1234 : }
1235 :
1236 411304 : if (this->outQueueSize >= routedlimit) {
1237 0 : if (get_msg_user(msg) != NAME_DISTRIBUTOR) {
1238 0 : warn("Congestion, throwing message away\n");
1239 0 : buf_discard(buf);
1240 : }
1241 0 : return;
1242 : }
1243 :
1244 : /* Bearer or less serious link congestion ? Try to bundle. */
1245 :
1246 411304 : if (((this->media->busy_links) ||
1247 : (this->outQueueSize >= this->windowLimit)) &&
1248 : (size < ((this->media->set.max_packet_sz * 2) / 3))) {
1249 0 : struct sk_buff *wrapperbuf = 0;
1250 0 : tipc_msg_hdr_t *targetmsg;
1251 0 : struct sk_buff *sourcebuf = buf;
1252 0 : tipc_msg_hdr_t *sourcemsg = buf_msg(sourcebuf);
1253 0 : uint sz = get_msg_size(sourcemsg);
1254 0 : tipc_msg_hdr_t *wrappermsg;
1255 :
1256 : /* Can last queued buffer be used? */
1257 0 : if (this->nextOut) {
1258 0 : struct sk_buff *b = this->lastOut;
1259 0 : uint rest = this->media->set.max_packet_sz -
1260 0 : align(get_msg_size(buf_msg(b)));
1261 :
1262 : dbg("Inquiring buf %p, remains %u\n", b, rest);
1263 0 : if ((sz <= rest)
1264 0 : && (get_msg_user(buf_msg(b)) == MSG_BUNDLER)
1265 0 : && (get_msg_type(buf_msg(b)) == OPEN_MSG)) {
1266 0 : wrapperbuf = b;
1267 : }
1268 : }
1269 :
1270 0 : if (!wrapperbuf) { /* Prepare a new buffer of the right kind */
1271 0 : tipc_msg_hdr_t wrapperhdr;
1272 :
1273 0 : set_msg_version(&wrapperhdr, MSG_VERSION_1);
1274 0 : set_msg_user(&wrapperhdr, MSG_BUNDLER);
1275 0 : set_hdr_size(&wrapperhdr, INTERNAL_HDR_SIZE);
1276 0 : set_msg_size(&wrapperhdr, INTERNAL_HDR_SIZE);
1277 0 : set_msg_type(&wrapperhdr, OPEN_MSG);
1278 0 : set_prev_node(&wrapperhdr, tipc_my_addr);
1279 : dbg("Preparing piggyback buf\n");
1280 0 : set_msg_count(&wrapperhdr, 0);
1281 0 : this->statistics.sentBundles++;
1282 0 : wrapperbuf =
1283 : buf_acquire(this->media->set.max_packet_sz);
1284 : assert(wrapperbuf);
1285 : memcpy(UD(wrapperbuf)->data, &wrapperhdr,
1286 0 : INTERNAL_HDR_SIZE);
1287 : }
1288 :
1289 0 : wrappermsg = buf_msg(wrapperbuf);
1290 0 : targetmsg = (tipc_msg_hdr_t *) (UD(wrapperbuf)->data +
1291 : align(get_msg_size
1292 0 : (buf_msg(wrapperbuf))));
1293 :
1294 : /* Now we have a buffer */
1295 0 : memcpy(targetmsg, sourcemsg, sz);
1296 0 : set_msg_count(wrappermsg, get_msg_count(wrappermsg) + 1);
1297 0 : this->statistics.sentBundled++;
1298 : dbg("Packed msg # %u(size %u octets) into pos %u in buf(#%u)\n",
1299 : get_msg_count(wrappermsg), sz,
1300 : align(get_msg_size(buf_msg(wrapperbuf))),
1301 : get_msg_seq_n(wrappermsg));
1302 0 : set_msg_size(wrappermsg, align(get_msg_size(wrappermsg)) + sz);
1303 : dbg_msg("PACKD:");
1304 0 : buf_discard(buf);
1305 0 : if (wrapperbuf != this->lastOut) {
1306 0 : this->statistics.deferredSendings++;
1307 0 : set_msg_seq_n(wrappermsg, mod(this->nxOutNo++));
1308 : dbg_msg(">QUEUING>");
1309 0 : link_addToOutQueue(this, wrapperbuf);
1310 0 : if (!this->nextOut)
1311 0 : this->nextOut = wrapperbuf;
1312 : /* Resolve possible deadlock */
1313 0 : if (!(this->media->busy_links)
1314 : && (!((++(this->delayedCount)) % 8))) {
1315 : dbg(" Assm:Sending STATE. Possible deadlock %u\n", this->delayedCount);
1316 0 : this->statistics.sentDeadlockAcks++;
1317 0 : link_protocolDataReq(this, STATE_MSG, 1, 0,
1318 : 0, 0);
1319 : }
1320 : }
1321 0 : return;
1322 : }
1323 :
1324 : /* ======= Message can be sent ========== */
1325 :
1326 822608 : set_msg_seq_n(msg, mod(this->nxOutNo++));
1327 822608 : set_msg_ack_n(msg, mod(this->nxInNo - 1));
1328 822608 : link_addToOutQueue(this, buf);
1329 411304 : if (!this->media->api->send_msg(this->media, &this->rep, buf)) {
1330 411304 : this->unackedWindow = 0;
1331 : } else {
1332 : dbg_msg(">BCONG>");
1333 0 : if (!(this->next))
1334 0 : media_schedule(this->media, this);
1335 0 : this->nextOut = buf;
1336 : }
1337 : }
1338 :
1339 : /*
1340 : * tipc_sendBuf is called from a driver user if data is already packed
1341 : * into a TipcBuffer. If certain conditions are met, data copying will
1342 : * be avoided.
1343 : */
1344 : uint
1345 : tipc_sendBuf(const TipcSendBufArgv * argv)
1346 34329 : {
1347 34329 : struct sk_buff *buf = argv->buf;
1348 34329 : Port *op = port_deref(argv->origport);
1349 34329 : Link *this = 0;
1350 34329 : tipc_msg_hdr_t *phdr;
1351 34329 : tipc_net_addr_t destnode;
1352 34329 : uint delay_sending = 0;
1353 34329 : uint msgsize, import;
1354 :
1355 34329 : if (!op || !buf || (argv->datasize > TIPC_MAX_DATA_SIZE)) {
1356 0 : return tipc_userError(tipc_invalid_args);
1357 : }
1358 34329 : phdr = port_phdr(op);
1359 34329 : if (!port_connected(op)) {
1360 63 : if (argv->addrtype == TIPC_PORT_ID) {
1361 0 : set_dest_node(phdr, argv->dest.id.node);
1362 0 : set_dest_port(phdr, argv->dest.id.port);
1363 0 : set_hdr_size(phdr, DIRECT_HDR_SIZE);
1364 0 : set_msg_type(phdr, TIPC_DIRECT_MSG);
1365 63 : } else if (argv->addrtype == TIPC_PORT_NAME) {
1366 63 : uint type = argv->dest.name.type;
1367 63 : uint inst = argv->dest.name.instance;
1368 63 : uint destport = 0;
1369 :
1370 63 : destnode = argv->dest.name.translationNode;
1371 63 : if (!destnode)
1372 63 : destnode = tipc_my_addr;
1373 63 : if (destnode < 512)
1374 0 : destnode <<= 24; /* Undocumented feature */
1375 : dbg("tipc_sendNamedBuf from port %u:Looking up <%u,%u>\n", argv->origport, type, inst);
1376 63 : set_name_type(phdr, type);
1377 63 : set_name_inst(phdr, inst);
1378 126 : set_hdr_size(phdr, LONG_HDR_SIZE);
1379 126 : set_msg_type(phdr, TIPC_NAMED_MSG);
1380 63 : if (tipc_addr_match(destnode, tipc_my_addr)) { /* First lookup here ? */
1381 63 : destport =
1382 : nametbl_translate(type, inst, &destnode);
1383 : }
1384 63 : set_dest_port(phdr, destport);
1385 63 : set_dest_node(phdr, destnode);
1386 : } else
1387 0 : return tipc_userError(tipc_illegal_operation);
1388 : }
1389 34329 : msgsize = get_hdr_size(phdr) + argv->datasize;
1390 68658 : set_msg_size(phdr, msgsize);
1391 : /* We have a complete header. Now, find destination link if any: */
1392 :
1393 34329 : destnode = get_dest_node(phdr);
1394 34329 : if (destnode != tipc_my_addr) {
1395 102912 : link_selectLocalLink(destnode, argv->origport, this);
1396 34304 : if (!this && is_local_delivery(phdr))
1397 0 : this = link_select(destnode, argv->origport);
1398 :
1399 0 : if (this) { /* Check sending conditions: */
1400 34304 : if (this->outQueueSize >= this->windowLimit) {
1401 14 : uint winlimit =
1402 : this->windowLimit +
1403 28 : (WINDOW_INCR_FACTOR * get_msg_user(phdr));
1404 14 : if (this->outQueueSize >= winlimit) { /* Link congestion */
1405 14 : if (!(++this->delayedCount % 16)) { /* Resolve possible deadlock */
1406 0 : this->statistics.
1407 : sentDeadlockAcks++;
1408 0 : link_protocolDataReq(this,
1409 : STATE_MSG,
1410 : 1, 0, 0,
1411 : 0);
1412 : }
1413 14 : this->statistics.windowOverflows++;
1414 14 : return link_schedulePort(this,
1415 : argv->
1416 : origport);
1417 : }
1418 0 : delay_sending = 1;
1419 : }
1420 34290 : if (this->media->busy_links) {
1421 34290 : delay_sending = 1;
1422 : }
1423 : }
1424 34442 : if (is_local_delivery(phdr) && is_direct_connect(phdr)) {
1425 0 : set_conn_seq_n(phdr, (get_conn_seq_n(phdr) + 1));
1426 : }
1427 : }
1428 :
1429 : /* Prepend header. Copy buffer if insufficient headroom: */
1430 :
1431 68630 : if (!buf_cprepend(buf, (__u8 *) phdr, get_hdr_size(phdr))) {
1432 0 : struct sk_buff *origbuf = buf;
1433 :
1434 0 : buf = buf_acquire(argv->datasize + LONG_HDR_SIZE);
1435 0 : if (!buf)
1436 0 : return 1;
1437 0 : memcpy(UD(buf)->data, phdr, get_hdr_size(phdr));
1438 : memcpy(UD(buf)->data + get_hdr_size(phdr), UD(origbuf)->data,
1439 0 : argv->datasize);
1440 0 : buf_discard(origbuf);
1441 : }
1442 :
1443 34315 : if (argv->origin.port) { /* Forwarded message ? */
1444 0 : tipc_msg_hdr_t *msg = buf_msg(buf);
1445 :
1446 0 : if (argv->addrtype == TIPC_NO_ADDR)
1447 0 : return tipc_userError(tipc_illegal_operation);
1448 0 : set_orig_port(msg, argv->origin.port);
1449 0 : set_orig_node(msg, argv->origin.node);
1450 0 : import = (((argv->importance) & 3) << 25);
1451 0 : import |= get_hdr_w(msg, 0) & ~(0xf << 25);
1452 0 : set_hdr_w(msg, 0, import);
1453 : }
1454 :
1455 34315 : if (!get_dest_port(phdr)) { /* Failed name lookup ? */
1456 1 : if (argv->addrtype != TIPC_PORT_NAME)
1457 0 : return tipc_userError(tipc_invalid_args);
1458 1 : port_rejectMsg(buf, tipc_no_portname);
1459 1 : return 0;
1460 : }
1461 :
1462 34314 : if (this) { /* node external message. Send it now */
1463 34290 : if (!delay_sending
1464 : && (msgsize <= this->media->set.max_packet_sz)) {
1465 22 : tipc_msg_hdr_t *msg = buf_msg(buf);
1466 :
1467 : set_hdr_w(msg, 1,
1468 : ((mod(this->nxInNo - 1) << 16) |
1469 22 : mod(this->nxOutNo++)));
1470 44 : link_addToOutQueue(this, buf);
1471 22 : if (!this->media->api->
1472 : send_msg(this->media, &this->rep, buf)) {
1473 22 : this->unackedWindow = 0;
1474 22 : return 0;
1475 : } else {
1476 : dbg_msg(">BCONG>");
1477 0 : if (!(this->next))
1478 0 : media_schedule(this->media, this);
1479 0 : this->nextOut = buf;
1480 : }
1481 0 : return 0;
1482 : }
1483 34268 : link_sendBuf(this, buf); /* Will piggyback or queue buffer */
1484 34268 : return 0;
1485 24 : } else if (destnode == tipc_my_addr) { /* node local message ? */
1486 24 : Port *port = port_deref(get_dest_port(phdr));
1487 :
1488 24 : if (!port)
1489 0 : port_rejectMsg(buf, tipc_no_remote_port);
1490 : else {
1491 24 : port_dispatch(port, buf);
1492 : }
1493 24 : return 0;
1494 : } else { /* There is no destination */
1495 :
1496 0 : port_rejectMsg(buf, tipc_no_remote_node);
1497 0 : return 0;
1498 : }
1499 : }
1500 :
1501 : uint
1502 : link_pushMessage(Link * this)
1503 0 : {
1504 :
1505 0 : struct sk_buff *buf = 0;
1506 :
1507 : /* Send one deferred retransmission, if there is any: */
1508 :
1509 0 : if (this->retransmitQueueLength) {
1510 0 : buf = this->firstOut;
1511 :
1512 : /* Step to the point where retransmission failed: */
1513 :
1514 0 : while ((buf != this->nextOut) &&
1515 : less(get_msg_seq_n(buf_msg(buf)),
1516 0 : this->retransmitQueueHead)) {
1517 0 : buf = UD(buf)->next;
1518 : }
1519 :
1520 : /* Buffers might have been released since last attempt.
1521 : Calculate new retransmission queue length. */
1522 :
1523 0 : if (buf
1524 : &&
1525 : (!lessEq
1526 : (get_msg_seq_n(buf_msg(buf)),
1527 0 : this->retransmitQueueHead))) {
1528 0 : uint head = get_msg_seq_n(buf_msg(buf));
1529 0 : uint tail =
1530 : mod(this->retransmitQueueHead +
1531 0 : this->retransmitQueueLength);
1532 :
1533 : /* Stop at 'nextOut' if 'retransmitQueueLength' goes beyond: */
1534 :
1535 0 : if (this->nextOut
1536 : &&
1537 : (lessEq
1538 0 : (get_msg_seq_n(buf_msg(this->nextOut)), tail))) {
1539 0 : tail =
1540 : mod(get_msg_seq_n(buf_msg(this->nextOut)) -
1541 0 : 1);
1542 : }
1543 :
1544 0 : if (lessEq(head, tail)) {
1545 0 : this->retransmitQueueHead = head;
1546 0 : this->retransmitQueueLength = mod(tail - head);
1547 : } else {
1548 0 : this->retransmitQueueHead =
1549 : this->retransmitQueueLength = 0;
1550 : }
1551 : }
1552 :
1553 : /* Send now, if there is anything: */
1554 :
1555 0 : if (((buf && (buf != this->nextOut)) && !skb_shared(buf))
1556 : && this->retransmitQueueLength) {
1557 0 : set_msg_ack_n(buf_msg(buf), mod(this->nxInNo - 1)); /* Update */
1558 0 : if (!this->media->api->
1559 : send_msg(this->media, &this->rep, buf)) {
1560 : dbg_msg(">DEF-RETR>");
1561 0 : this->retransmitQueueHead =
1562 : mod(++(this->retransmitQueueHead));
1563 0 : this->retransmitQueueLength--;
1564 0 : return 0;
1565 : } else {
1566 : dbg_msg("|>DEF-RETR>");
1567 0 : return PUSH_FAILED;
1568 : }
1569 : }
1570 : /* In case 'retransmitQueueLength' from the
1571 : // beginning was longer than number of sent/
1572 : // unacked messages,retransmit might terminate
1573 : // because an unsent message ('nextOut') was
1574 : // encountered,'retransmitQueueLength' might
1575 : // still be non-zero here. Correct this now. */
1576 :
1577 0 : this->retransmitQueueLength = 0;
1578 : }
1579 :
1580 : /* Send deferred protocol message, if any: */
1581 :
1582 0 : if (this->protocolMsgQueue) {
1583 0 : buf = this->protocolMsgQueue;
1584 0 : set_msg_ack_n(buf_msg(buf), mod(this->nxInNo - 1));
1585 :
1586 0 : if (!this->media->api->send_msg(this->media, &this->rep, buf)) {
1587 : dbg_msg(">DEF-PROT>");
1588 0 : this->unackedWindow = 0;
1589 0 : this->protocolMsgQueue = 0;
1590 0 : this->statistics.pushed++;
1591 0 : return 0;
1592 : } else {
1593 : dbg_msg("|>DEF-PROT>");
1594 0 : return PUSH_FAILED;
1595 : }
1596 : }
1597 :
1598 : /* Send one deferred data message, if any and if
1599 : send window not full: */
1600 :
1601 0 : buf = this->nextOut;
1602 0 : if (buf) {
1603 0 : if (mod(get_msg_seq_n(buf_msg(buf)) -
1604 0 : get_msg_seq_n(buf_msg(this->firstOut))) <
1605 : this->windowLimit) {
1606 0 : if (!skb_shared(buf)) {
1607 0 : set_msg_ack_n(buf_msg(buf), mod(this->nxInNo - 1)); /* Update */
1608 0 : if (!this->media->api->
1609 : send_msg(this->media, &this->rep, buf)) {
1610 0 : this->statistics.pushed++;
1611 : dbg_msg(">DEF-DATA>");
1612 0 : this->nextOut = UD(buf)->next;
1613 0 : return 0;
1614 : } else {
1615 : dbg_msg("|>DEF-DATA>");
1616 0 : return PUSH_FAILED;
1617 : }
1618 : }
1619 : }
1620 : }
1621 0 : return PUSH_FINISHED;
1622 : }
1623 :
1624 : void
1625 : link_pushQueue(Link * this)
1626 0 : {
1627 0 : uint res = 0;
1628 :
1629 0 : while (res == 0) {
1630 0 : res = link_pushMessage(this);
1631 : }
1632 0 : if ((res == PUSH_FAILED) && !(this->next))
1633 0 : media_schedule(this->media, this);
1634 : }
1635 :
1636 : uint retransmitting = 0;
1637 : void
1638 : link_retransmit(Link * this, uint retransmits)
1639 13 : {
1640 13 : struct sk_buff *buf = this->firstOut;
1641 :
1642 : dbg("Retransmitting %u\n", retransmits);
1643 :
1644 13 : if ((this->media->busy_links) && (buf && !skb_shared(buf))) {
1645 : dbg_msg(">NO_RETR->BCONG>");
1646 0 : if (!(this->next))
1647 0 : media_schedule(this->media, this);
1648 0 : this->retransmitQueueHead = get_msg_seq_n(buf_msg(buf));
1649 0 : this->retransmitQueueLength = retransmits;
1650 0 : return;
1651 : }
1652 13 : retransmitting = 1;
1653 22 : while (retransmits
1654 : && ((buf != this->nextOut) && buf && !skb_shared(buf))) {
1655 9 : tipc_msg_hdr_t *msg = buf_msg(buf);
1656 :
1657 18 : set_msg_ack_n(msg, mod(this->nxInNo - 1));
1658 9 : if (!this->media->api->send_msg(this->media, &this->rep, buf)) {
1659 : dbg_msg(">RETR>");
1660 0 : buf = UD(buf)->next;
1661 9 : retransmits--;
1662 9 : this->statistics.retransmitted++;
1663 : } else {
1664 : dbg_msg(">RETR->BCONG>");
1665 0 : if (!(this->next))
1666 0 : media_schedule(this->media, this);
1667 0 : this->retransmitQueueHead = get_msg_seq_n(buf_msg(buf));
1668 0 : this->retransmitQueueLength = retransmits;
1669 0 : return;
1670 : }
1671 : }
1672 13 : this->retransmitQueueHead = this->retransmitQueueLength = 0;
1673 13 : retransmitting = 0;
1674 : }
1675 :
1676 : /*
1677 : * Put a message into correct position (in sequence)
1678 : * in reception queue.
1679 : */
1680 : uint deferred = 0;
1681 : void
1682 : link_addToDeferredInQueue(Link * this, struct sk_buff *buf)
1683 0 : {
1684 0 : uint upper;
1685 0 : uint lower;
1686 0 : struct sk_buff *crs;
1687 :
1688 0 : deferred = 1;
1689 0 : this->nonSequenceCount++;
1690 0 : this->statistics.deferredReceptions++;
1691 : /* Reception queue empty ? */
1692 :
1693 0 : if (!this->oldestDeferredIn) {
1694 0 : this->deferredInQueueSize = 1;
1695 0 : this->oldestDeferredIn = this->newestDeferredIn = buf;
1696 0 : UD(buf)->next = 0;
1697 0 : link_protocolDataReq(this, STATE_MSG, 0, 0, 0, 0);
1698 0 : return;
1699 : }
1700 :
1701 : /* Put message last in queue ? */
1702 :
1703 0 : upper = mod(this->nxInNo + 127);
1704 0 : lower = get_msg_seq_n(buf_msg(this->newestDeferredIn));
1705 0 : if (between(lower, upper, get_msg_seq_n(buf_msg(buf)))) {
1706 0 : this->deferredInQueueSize++;
1707 0 : UD(this->newestDeferredIn)->next = buf;
1708 0 : this->newestDeferredIn = buf;
1709 0 : UD(buf)->next = 0;
1710 0 : if (!(this->nonSequenceCount % 6)
1711 : || (this->deferredInQueueSize > DEF_QUEUE_LIMIT)) {
1712 0 : link_protocolDataReq(this, STATE_MSG, 0, 0, 0, 0);
1713 : }
1714 0 : return;
1715 : }
1716 :
1717 : /* Put message first in queue ? */
1718 :
1719 0 : lower = this->nxInNo;
1720 0 : upper = get_msg_seq_n(buf_msg(this->oldestDeferredIn));
1721 0 : if (between(lower, upper, get_msg_seq_n(buf_msg(buf)))) {
1722 0 : this->deferredInQueueSize++;
1723 0 : UD(buf)->next = this->oldestDeferredIn;
1724 0 : this->oldestDeferredIn = buf;
1725 0 : if (!(this->nonSequenceCount % 6) ||
1726 : (this->deferredInQueueSize > DEF_QUEUE_LIMIT)) {
1727 0 : link_protocolDataReq(this, STATE_MSG, 0, 0, 0, 0);
1728 : }
1729 0 : return;
1730 : }
1731 :
1732 : /* Scan through queue and find correct position: */
1733 :
1734 0 : crs = this->oldestDeferredIn;
1735 0 : do {
1736 0 : lower = get_msg_seq_n(buf_msg(crs));
1737 0 : upper =
1738 0 : UD(crs)->next ? get_msg_seq_n(buf_msg(UD(crs)->next)) :
1739 : lower;
1740 0 : if (between(lower, upper, get_msg_seq_n(buf_msg(buf)))) {
1741 0 : this->deferredInQueueSize++;
1742 0 : UD(buf)->next = UD(crs)->next;
1743 0 : UD(crs)->next = buf;
1744 0 : if (!(this->nonSequenceCount % 6)
1745 : || (this->deferredInQueueSize > DEF_QUEUE_LIMIT)) {
1746 0 : link_protocolDataReq(this, STATE_MSG, 0, 0,
1747 : 0, 0);
1748 : }
1749 0 : return;
1750 : }
1751 0 : crs = UD(crs)->next;
1752 0 : }
1753 : while (upper != lower);
1754 :
1755 : /* Message does not fit anywhere. Discard. */
1756 0 : buf_discard(buf);
1757 : }
1758 :
1759 : /* Send protocol message to remote party: */
1760 : void
1761 : link_protocolDataReq(Link * this, uint msgType, uint prob,
1762 : uint gap, uint tolerance, uint priority)
1763 37399 : {
1764 37399 : struct sk_buff *buf = this->protocolBuf;
1765 37399 : struct sk_buff *defrd = this->oldestDeferredIn;
1766 37399 : tipc_msg_hdr_t *msg = buf_msg(buf);
1767 :
1768 37399 : if (this->expectedMsgCount)
1769 37399 : return;
1770 74798 : set_msg_type(msg, msgType);
1771 74798 : set_network_id(msg, this->media->net_id);
1772 :
1773 37399 : if (msgType == STATE_MSG) {
1774 74790 : set_msg_tolerance(msg, tolerance);
1775 74790 : set_link_priority(msg, priority);
1776 74790 : set_msg_ack_n(msg, mod(this->nxInNo - 1));
1777 74790 : set_msg_probe(msg, prob != 0);
1778 37395 : if (prob) {
1779 226 : this->statistics.sentProbes++;
1780 : }
1781 37395 : if (gap)
1782 2 : this->statistics.sentNacks++;
1783 : set_seq_gap(msg,
1784 : defrd ? mod(get_msg_seq_n(buf_msg(defrd)) -
1785 74790 : this->nxInNo) : gap);
1786 : set_next_sent(msg,
1787 : this->
1788 : nextOut ? get_msg_seq_n(buf_msg(this->nextOut)) :
1789 74790 : mod(this->nxOutNo));
1790 37395 : this->statistics.sentStates++;
1791 : } else { /* RESET_MSG or ACTIVATE_MSG */
1792 :
1793 8 : set_msg_ack_n(msg, mod(this->resetCheckpoint - 1));
1794 8 : set_seq_gap(msg, 0);
1795 8 : set_next_sent(msg, 1);
1796 8 : set_msg_tolerance(msg, this->tolerance);
1797 8 : set_link_priority(msg, this->priority);
1798 : }
1799 : dbg_msg(">>> prot msg at %s (id %u) with media id %u\n",
1800 : this->media->name, this->media->id, get_media_id(msg));
1801 37399 : if (!(this->media->busy_links)) {
1802 37399 : if (skb_shared(buf)) {
1803 37 : buf = buf_copy(buf, UD(buf)->data);
1804 : }
1805 37399 : if (!this->media->api->send_msg(this->media, &this->rep, buf)) {
1806 37399 : this->unackedWindow = 0;
1807 37399 : if (buf != this->protocolBuf)
1808 37 : link_addToQuarantine(this, buf);
1809 0 : return;
1810 : }
1811 0 : if (buf != this->protocolBuf)
1812 0 : link_addToQuarantine(this, buf);
1813 : }
1814 : dbg_msg(">BCONG>");
1815 0 : if (!(this->next))
1816 0 : media_schedule(this->media, this);
1817 0 : this->protocolMsgQueue = buf;
1818 : }
1819 :
1820 : /* Receive protocol message: */
1821 : void
1822 : link_protocolDataInd(Link * this, struct sk_buff *buf)
1823 36029 : {
1824 36029 : if (!this->expectedMsgCount) {
1825 36029 : tipc_msg_hdr_t *msg = buf_msg(buf);
1826 :
1827 : /* Network (switch) id propagates through the network, and may */
1828 : /* change at any time. node with lowest address rules */
1829 36029 : if ((this->media->net_id != get_network_id(msg)) &&
1830 0 : (tipc_my_addr > get_prev_node(msg))) {
1831 0 : this->media->net_id = get_network_id(msg);
1832 : }
1833 36029 : switch (get_msg_type(msg)) {
1834 : case RESET_MSG:
1835 : {
1836 0 : if (!link_working_unknown(this)
1837 0 : && (get_msg_session(msg) ==
1838 : this->remoteSession)) {
1839 0 : info("TIPC: Received duplicate RESET msg %u\n", get_msg_session(msg));
1840 0 : break;
1841 : }
1842 : }
1843 : case ACTIVATE_MSG:
1844 : {
1845 : /* Update link according other endpoint's values: */
1846 4 : this->remoteBearerId = get_media_id(msg); /* Needed for changeover */
1847 4 : if (get_msg_tolerance(msg) > this->tolerance) {
1848 0 : link_setTolerance(this,
1849 : get_msg_tolerance
1850 0 : (msg));
1851 : }
1852 4 : if (get_link_priority(msg) > this->priority) {
1853 0 : this->priority = get_link_priority(msg);
1854 : }
1855 8 : if (msg_data_size(msg)) { /* Compatibility */
1856 4 : char stripped_name[64];
1857 4 : char *p =
1858 8 : strchr(msg_data_start(msg), ':');
1859 4 : if (!p++) {
1860 4 : p = msg_data_start(msg);
1861 : }
1862 4 : strcpy(stripped_name, p);
1863 4 : if (stripped_name
1864 : [strlen(stripped_name) - 1] !=
1865 : '>') {
1866 4 : strcat(stripped_name, ">");
1867 : }
1868 4 : sprintf((strrchr(this->rep.name, ':') +
1869 : 1), "%s", stripped_name);
1870 : }
1871 4 : link_handleStateEvent(this, get_msg_type(msg));
1872 4 : this->remoteSession = get_msg_session(msg);
1873 4 : if (!get_msg_session(msg)) {
1874 0 : set_msg_session(buf_msg(this->protocolBuf), 0); /* Compatibility */
1875 : }
1876 0 : break;
1877 : }
1878 : case STATE_MSG:
1879 : {
1880 36025 : uint recGap = 0;
1881 :
1882 36025 : if (get_msg_tolerance(msg))
1883 0 : link_setTolerance(this,
1884 : get_msg_tolerance
1885 0 : (msg));
1886 36025 : if (get_link_priority(msg)
1887 0 : && (get_link_priority(msg) !=
1888 : this->priority)) {
1889 : dbg("rec prio %u, own %u, resetting...\n", get_link_priority(msg), this->priority);
1890 0 : this->priority = get_link_priority(msg);
1891 0 : link_reset(this); /* Enforce the change to take effect */
1892 0 : return;
1893 : }
1894 36025 : link_handleStateEvent(this, TRAFFIC_MSG_EVT);
1895 36025 : this->statistics.receivedStates++;
1896 36025 : if (link_reset_unknown(this))
1897 36025 : break;
1898 : /* After changeover this condition might be false: */
1899 36025 : if (lessEq(this->nxInNo, get_next_sent(msg))) {
1900 36025 : recGap =
1901 : mod(get_next_sent(msg) -
1902 36025 : this->nxInNo);
1903 : dbg_msg
1904 : (" protoInd: recGap = %u = (%u-%u)\n",
1905 : recGap, get_next_sent(msg),
1906 : this->nxInNo);
1907 : }
1908 36025 : if (get_seq_gap(msg)) {
1909 : dbg_msg("With Gap:");
1910 13 : this->statistics.receivedNacks++;
1911 13 : link_retransmit(this, get_seq_gap(msg));
1912 : }
1913 36025 : if (is_msg_probe(msg)) {
1914 581 : this->statistics.receivedProbes++;
1915 : }
1916 36025 : if (recGap || (is_msg_probe(msg))) {
1917 583 : link_protocolDataReq(this, STATE_MSG,
1918 : 0, recGap, 0, 0);
1919 : }
1920 : break;
1921 : }
1922 : default:
1923 : {
1924 : dbg_msg("<DISCARDING UNKOWN<");
1925 : }
1926 : }
1927 : }
1928 36029 : buf_discard(buf);
1929 : }
1930 :
1931 : void
1932 : link_specialMsgInd(Link * this, struct sk_buff *buf)
1933 411038 : {
1934 411038 : tipc_msg_hdr_t *msg = buf_msg(buf);
1935 :
1936 411038 : switch (get_msg_user(msg)) {
1937 : case MSG_BUNDLER:
1938 : {
1939 0 : link_bundlerDataInd(this, buf);
1940 411032 : return;
1941 : }
1942 : case SEGMENTATION_MANAGER:
1943 : {
1944 411032 : link_segmDataInd(this, buf);
1945 0 : return;
1946 : }
1947 : case ROUTING_MANAGER:
1948 : {
1949 0 : tipc_cluster_handleroutingtablemsg(buf);
1950 0 : break;
1951 : }
1952 : case NAME_DISTRIBUTOR:
1953 : {
1954 4 : if (get_dest_node(msg) == tipc_my_addr) {
1955 4 : tipc_named_recv(buf);
1956 : } else {
1957 0 : tipc_network_routemessage(buf);
1958 : }
1959 0 : break;
1960 : }
1961 : case CONNECTION_MANAGER:
1962 : {
1963 0 : if (get_dest_node(msg) == tipc_my_addr) {
1964 0 : port_protocolDataInd(buf);
1965 : } else {
1966 : dbg_msg("SPEC: CONNMAN: ");
1967 0 : tipc_network_routemessage(buf);
1968 : }
1969 0 : break;
1970 : }
1971 :
1972 : case CHANGEOVER_PROTOCOL:
1973 : {
1974 2 : link_changeoverDataInd(buf);
1975 2 : break;
1976 : }
1977 :
1978 : default:
1979 : {
1980 : dbg_msg("Throwing away unrecognizable message\n");
1981 0 : buf_discard(buf);
1982 6 : return;
1983 : }
1984 : }
1985 6 : link_handleStateEvent(this, TRAFFIC_MSG_EVT);
1986 : }
1987 :
1988 : void
1989 : link_handleTimeout(Link * this)
1990 1552 : {
1991 1552 : this->timerRef = 0;
1992 1552 : this->statistics.accuQueueSize += this->outQueueSize;
1993 1552 : this->statistics.queueSizeCounts++;
1994 1552 : link_releaseQuarantine(this);
1995 1552 : if (this->outQueueSize > this->statistics.maxQueueSize) {
1996 3 : this->statistics.maxQueueSize = this->outQueueSize;
1997 : }
1998 1552 : if (this->firstOut) {
1999 379 : tipc_msg_hdr_t *msg = buf_msg(this->firstOut);
2000 379 : uint length = get_msg_size(msg);
2001 :
2002 379 : if ((get_msg_user(msg) == SEGMENTATION_MANAGER)
2003 370 : && (get_msg_type(msg) == FIRST_SEGMENT)) {
2004 87 : length = get_msg_size(get_encap_msg(msg));
2005 : }
2006 379 : if (length) {
2007 379 : this->statistics.accuPackLength += length;
2008 379 : this->statistics.packLengthCounts++;
2009 379 : if (length <= 64)
2010 7 : this->statistics.msgLengthProfile[0]++;
2011 372 : else if (length <= 256)
2012 2 : this->statistics.msgLengthProfile[1]++;
2013 370 : else if (length <= 1024)
2014 0 : this->statistics.msgLengthProfile[2]++;
2015 370 : else if (length <= 4096)
2016 283 : this->statistics.msgLengthProfile[3]++;
2017 87 : else if (length <= 16384)
2018 0 : this->statistics.msgLengthProfile[4]++;
2019 87 : else if (length <= 32768)
2020 87 : this->statistics.msgLengthProfile[5]++;
2021 : else
2022 0 : this->statistics.msgLengthProfile[6]++;
2023 : }
2024 : }
2025 1552 : if (link_working_working(this) && (this->nxInNo != this->checkpoint)) {
2026 1330 : this->checkpoint = this->nxInNo;
2027 1330 : link_setTimer(this, this->continuityInterval);
2028 : } else
2029 222 : link_handleStateEvent(this, TIMEOUT_EVT);
2030 : }
2031 :
2032 : /* Changeover management: */
2033 : void
2034 : link_changeoverSend(Link * this, tipc_msg_hdr_t * wh, struct sk_buff *ibuf)
2035 0 : {
2036 0 : Link *replacement;
2037 0 : struct sk_buff *buf;
2038 0 : tipc_msg_hdr_t *msg = buf_msg(ibuf);
2039 0 : uint length = get_msg_size(msg);
2040 :
2041 0 : set_link_selector(wh, get_link_selector(msg));
2042 0 : set_msg_size(wh, length + INTERNAL_HDR_SIZE);
2043 0 : buf = buf_acquire(length + INTERNAL_HDR_SIZE);
2044 0 : memcpy(UD(buf)->data, wh, INTERNAL_HDR_SIZE);
2045 0 : memcpy(UD(buf)->data + INTERNAL_HDR_SIZE, UD(ibuf)->data, length);
2046 0 : replacement = link_select(this->rep.addr, get_link_selector(msg));
2047 : assert(replacement);
2048 0 : replacement->changingOver = 1;
2049 0 : link_sendBuf(replacement, buf);
2050 0 : replacement->changingOver = 0;
2051 : }
2052 :
2053 : /*
2054 : * changeoverReq: Send whole message queue via a link
2055 : * belonging to another media.
2056 : */
2057 : void
2058 : link_changeoverReq(Link * this)
2059 0 : {
2060 0 : uint msgcount = this->outQueueSize;
2061 0 : struct sk_buff *crs;
2062 :
2063 : /* Build header: */
2064 0 : tipc_msg_hdr_t wheader;
2065 :
2066 0 : memset(&wheader, 0, sizeof (wheader));
2067 0 : set_msg_version(&wheader, MSG_VERSION_1);
2068 0 : set_msg_user(&wheader, CHANGEOVER_PROTOCOL);
2069 0 : set_prev_node(&wheader, tipc_my_addr);
2070 0 : set_hdr_size(&wheader, INTERNAL_HDR_SIZE);
2071 0 : set_msg_type(&wheader, ORIGINAL_MSG);
2072 0 : set_media_id(&wheader, this->remoteBearerId);
2073 : dbg("CHO:Link to %x(%s): using detination media id %u\n",
2074 : this->rep.addr, (this->media)->name, this->remoteBearerId);
2075 : /* Piggybacked messages must be counted separately: */
2076 0 : for (crs = this->firstOut; crs != 0; crs = UD(crs)->next) {
2077 0 : if (get_msg_user(buf_msg(crs)) == MSG_BUNDLER) {
2078 0 : msgcount += (get_msg_count(buf_msg(crs)) - 1);
2079 : }
2080 : }
2081 0 : set_msg_count(&wheader, msgcount);
2082 0 : set_msg_size(&wheader, INTERNAL_HDR_SIZE);
2083 0 : if (!this->firstOut) {
2084 0 : struct sk_buff *buf;
2085 0 : Link *replacement;
2086 :
2087 0 : set_msg_type(&wheader, INFO_MSG);
2088 0 : set_link_selector(&wheader, 1u); /* Value does not really matter */
2089 0 : buf = buf_acquire(INTERNAL_HDR_SIZE);
2090 0 : memcpy(UD(buf)->data, &wheader, INTERNAL_HDR_SIZE);
2091 0 : set_msg_size(&wheader, INTERNAL_HDR_SIZE);
2092 0 : replacement = link_select(this->rep.addr, 1);
2093 : assert(replacement);
2094 0 : replacement->changingOver = 1;
2095 0 : link_sendBuf(replacement, buf);
2096 0 : replacement->changingOver = 0;
2097 0 : return;
2098 : } else {
2099 0 : struct sk_buff *iter = this->firstOut;
2100 :
2101 0 : while (iter) {
2102 0 : tipc_msg_hdr_t *msg = buf_msg(iter);
2103 :
2104 : /* Bundler messages must be split, because their parts
2105 : may have different link selectors: */
2106 0 : if (get_msg_user(msg) == MSG_BUNDLER) {
2107 0 : uint msgcount = get_msg_count(msg);
2108 0 : __u8 *pos = UD(iter)->data + INTERNAL_HDR_SIZE;
2109 0 : struct sk_buff *obuf;
2110 :
2111 0 : while (msgcount--) {
2112 0 : obuf = buf_copy(iter, pos);
2113 : assert(obuf);
2114 : set_msg_seq_n(buf_msg(obuf),
2115 0 : get_msg_seq_n(msg));
2116 0 : pos +=
2117 0 : align(get_msg_size(buf_msg(obuf)));
2118 : dbg_msg(">COA>");
2119 : dbg("(%u)\n", msgcount);
2120 0 : link_changeoverSend(this, &wheader,
2121 : obuf);
2122 0 : buf_discard(obuf);
2123 : }
2124 : } else {
2125 : dbg_msg(">COO>");
2126 0 : link_changeoverSend(this, &wheader, iter);
2127 : }
2128 0 : iter = UD(iter)->next;
2129 : }
2130 : }
2131 : }
2132 :
2133 : void
2134 : link_duplicateReq(Link * this, Link * target)
2135 2 : {
2136 2 : struct sk_buff *iter;
2137 :
2138 : /* Build header: */
2139 :
2140 2 : tipc_msg_hdr_t wheader;
2141 :
2142 2 : memset(&wheader, 0, INTERNAL_HDR_SIZE);
2143 2 : set_prev_node(&wheader, tipc_my_addr);
2144 4 : set_msg_version(&wheader, MSG_VERSION_1);
2145 4 : set_msg_user(&wheader, CHANGEOVER_PROTOCOL);
2146 4 : set_hdr_size(&wheader, INTERNAL_HDR_SIZE);
2147 4 : set_msg_type(&wheader, DUPLICATE_MSG);
2148 4 : set_media_id(&wheader, this->remoteBearerId);
2149 4 : set_msg_count(&wheader, this->outQueueSize);
2150 2 : iter = this->firstOut;
2151 2 : while (iter) {
2152 2 : struct sk_buff *outbuf;
2153 2 : tipc_msg_hdr_t *msg = buf_msg(iter);
2154 2 : uint length = get_msg_size(buf_msg(iter));
2155 :
2156 2 : if (get_msg_user(msg) == MSG_BUNDLER) {
2157 : /* Avoid that more messages are appended */
2158 0 : set_msg_type(msg, CLOSED_MSG);
2159 : }
2160 4 : set_msg_ack_n(msg, mod(this->nxInNo - 1)); /* Update */
2161 8 : set_link_selector(&wheader, get_link_selector(msg));
2162 4 : set_msg_size(&wheader, length + INTERNAL_HDR_SIZE);
2163 2 : outbuf = buf_acquire(length + INTERNAL_HDR_SIZE);
2164 2 : memcpy(UD(outbuf)->data, &wheader, INTERNAL_HDR_SIZE);
2165 : memcpy(UD(outbuf)->data + INTERNAL_HDR_SIZE, UD(iter)->data,
2166 2 : length);
2167 : dbg_msg(">COD>");
2168 2 : link_sendBuf(target, outbuf);
2169 2 : iter = UD(iter)->next;
2170 : }
2171 : }
2172 :
2173 : /*
2174 : * changeoverDataInd: Receive rerouted message sent via a link
2175 : * belonging to another media.
2176 : */
2177 : void
2178 : link_changeoverDataInd(struct sk_buff *wBuf)
2179 2 : {
2180 2 : Link *this = 0;
2181 2 : tipc_msg_hdr_t *msg;
2182 2 : tipc_msg_hdr_t *wmsg = buf_msg(wBuf);
2183 2 : uint msgType = get_msg_type(wmsg);
2184 2 : uint mediaNo = get_media_id(wmsg);
2185 2 : uint msgCount = get_msg_count(wmsg);
2186 2 : struct tipc_media proxyBearer;
2187 :
2188 : assert(mediaNo < 8);
2189 :
2190 : /* Find receiving link object, if any: */
2191 4 : this = link_find(get_prev_node(wmsg), mediaNo);
2192 2 : if (!this) {
2193 : dbg_msg("I hope this link just was removed!!");
2194 0 : buf_discard(wBuf);
2195 0 : return;
2196 : }
2197 :
2198 2 : if (msgType == INFO_MSG) {
2199 : dbg("<COINFO\n");
2200 0 : if (link_working_working(this) || link_working_unknown(this)) {
2201 : dbg("resetting link\n");
2202 0 : link_reset(this);
2203 : }
2204 0 : this->expectedMsgCount = 0; /* ==> deblock link */
2205 0 : buf_discard(wBuf);
2206 0 : return;
2207 : }
2208 :
2209 2 : msg = (tipc_msg_hdr_t *) (UD(wBuf)->data + INTERNAL_HDR_SIZE);
2210 :
2211 : /* Is message a duplicate? */
2212 :
2213 2 : if (msgType == DUPLICATE_MSG) {
2214 2 : uint length;
2215 2 : struct sk_buff *buf;
2216 :
2217 4 : if (less(get_msg_seq_n(msg), this->nxInNo)) {
2218 : dbg_msg("~COD~");
2219 : dbg("(%u<%u)\n", get_msg_seq_n(msg), this->nxInNo);
2220 2 : buf_discard(wBuf);
2221 2 : return;
2222 : }
2223 : /* Unwrap message; */
2224 :
2225 0 : length = get_msg_size(wmsg) - INTERNAL_HDR_SIZE;
2226 0 : buf = buf_acquire(length);
2227 : memcpy(UD(buf)->data, UD(wBuf)->data + INTERNAL_HDR_SIZE,
2228 0 : length);
2229 0 : buf_discard(wBuf);
2230 :
2231 : /* Create temporary 'media': */
2232 0 : proxyBearer.id = mediaNo;
2233 0 : UD(buf)->next = 0;
2234 : dbg_msg("<COD<");
2235 : dbg("(%u >= %u)\n", get_msg_seq_n(msg), this->nxInNo);
2236 0 : media_recv_msg((struct tipc_media *) &proxyBearer, buf);
2237 0 : return;
2238 : }
2239 :
2240 : /* Original message: */
2241 :
2242 : else {
2243 : assert(msgType == ORIGINAL_MSG);
2244 0 : if (link_working_working(this) || link_working_unknown(this)) {
2245 : warn("Rec changeover, orig msg, resetting link %p\n",
2246 0 : this);
2247 0 : link_reset(this);
2248 : }
2249 :
2250 0 : if (this->expectedMsgCount == BLOCKED) { /* First message */
2251 0 : this->expectedMsgCount = msgCount;
2252 : }
2253 0 : if (msgCount == 0) {
2254 : #ifdef CONFIG_TIPC_DBG_BUF
2255 : link_dump(this);
2256 : #endif
2257 : }
2258 0 : if (msgCount == 0) { /* Overdue changeover. Ignore */
2259 0 : info("Overdue Changeover Msg received!!\n");
2260 0 : buf_discard(wBuf);
2261 0 : return;
2262 : }
2263 0 : if (this->expectedMsgCount <= 0) {
2264 : dbg("expectedMsgCount = %u \n", this->expectedMsgCount);
2265 : #ifdef CONFIG_TIPC_DBG_BUF
2266 : link_dump(this);
2267 : #endif
2268 : }
2269 : assert(this->expectedMsgCount > 0);
2270 0 : if (less(get_msg_seq_n(msg), this->resetCheckpoint)) {
2271 : dbg_msg("~COO~");
2272 : dbg("(%u<%u)\n", get_msg_seq_n(msg),
2273 : this->resetCheckpoint);
2274 0 : buf_discard(wBuf);
2275 : } else {
2276 : /* Unwrap message: */
2277 0 : uint length = get_msg_size(wmsg) - INTERNAL_HDR_SIZE;
2278 0 : struct sk_buff *buf;
2279 :
2280 0 : buf = buf_acquire(length);
2281 : memcpy(UD(buf)->data,
2282 0 : UD(wBuf)->data + INTERNAL_HDR_SIZE, length);
2283 : dbg_msg("<COO<");
2284 : dbg("(%u>=%u)\n", get_msg_seq_n(msg),
2285 : this->resetCheckpoint);
2286 0 : if (is_data_msg(buf_msg(buf))) {
2287 : dbg_msg("Routing received unwrapped: ");
2288 0 : tipc_network_routemessage(buf);
2289 : } else {
2290 0 : link_specialMsgInd(this, buf);
2291 : }
2292 0 : buf_discard(wBuf);
2293 : }
2294 0 : this->expectedMsgCount--;
2295 : }
2296 : }
2297 :
2298 : /* Bundler functionality: */
2299 : void
2300 : link_bundlerDataInd(Link * this, struct sk_buff *buf)
2301 0 : {
2302 0 : uint msgcount = get_msg_count(buf_msg(buf));
2303 0 : __u8 *pos = UD(buf)->data + INTERNAL_HDR_SIZE;
2304 0 : struct sk_buff *obuf;
2305 :
2306 0 : this->statistics.receivedBundles++;
2307 0 : while (msgcount--) {
2308 0 : obuf = buf_copy(buf, pos);
2309 : assert(obuf);
2310 0 : pos += align(get_msg_size(buf_msg(obuf)));
2311 0 : this->statistics.receivedBundled++;
2312 0 : if (is_data_msg(buf_msg(obuf))) {
2313 : dbg_msg("Routing received unbundled: ");
2314 0 : tipc_network_routemessage(obuf);
2315 : } else {
2316 : dbg_msg("SPEC MSG UPACK::");
2317 0 : link_specialMsgInd(this, obuf);
2318 : }
2319 : }
2320 0 : buf_discard(buf);
2321 : }
2322 :
2323 : /* Segmentation/desegmentation: */
2324 : void
2325 : link_segmReset(Link * this)
2326 4 : {
2327 4 : struct sk_buff *buf = this->desegm_buf;
2328 :
2329 4 : while (buf) {
2330 0 : struct sk_buff *next = UD(buf)->next;
2331 :
2332 0 : buf_discard(buf);
2333 0 : buf = next;
2334 : }
2335 4 : this->desegm_buf = 0;
2336 : }
2337 :
2338 : uint
2339 : link_sendLongMsg(Link * this, const TipcSendMsgArgv * argv,
2340 : tipc_msg_hdr_t * phdr)
2341 0 : {
2342 0 : uint maxPacketSize = this->media->set.max_packet_sz;
2343 0 : uint segmentLimit = maxPacketSize - INTERNAL_HDR_SIZE;
2344 0 : uint rest = get_msg_size(phdr) - get_hdr_size(phdr);
2345 0 : tipc_msg_hdr_t sheader;
2346 0 : struct sk_buff *buf;
2347 0 : uint hsize;
2348 0 : uint winlimit = this->windowLimit;
2349 :
2350 0 : if (this->outQueueSize >= winlimit) {
2351 0 : winlimit += WINDOW_INCR_FACTOR * get_msg_user(phdr);
2352 0 : if (this->outQueueSize >= winlimit) {
2353 : /* Link congestion. Resolve possible deadlock */
2354 0 : if (!(++this->delayedCount % 16)) {
2355 0 : this->statistics.sentDeadlockAcks++;
2356 0 : link_protocolDataReq(this, STATE_MSG, 1, 0,
2357 : 0, 0);
2358 : }
2359 0 : this->statistics.windowOverflows++;
2360 : dbg("LINK: Returning EBUSY: Queue is %u,Window is %u \n", this->outQueueSize, winlimit);
2361 0 : return link_schedulePort(this, argv->origport);
2362 : }
2363 : }
2364 0 : if (rest > TIPC_MAX_DATA_SIZE) {
2365 0 : return tipc_userError(tipc_oversized_message);
2366 : }
2367 :
2368 : /* Prepare reusable segment header: */
2369 :
2370 0 : memset(&sheader, 0, INTERNAL_HDR_SIZE);
2371 0 : set_msg_version(&sheader, MSG_VERSION_1);
2372 0 : set_msg_user(&sheader, SEGMENTATION_MANAGER);
2373 0 : set_prev_node(&sheader, tipc_my_addr);
2374 0 : set_link_selector(&sheader, get_link_selector(phdr));
2375 0 : set_msg_size(&sheader, maxPacketSize);
2376 0 : set_hdr_size(&sheader, INTERNAL_HDR_SIZE);
2377 0 : set_msg_type(&sheader, FIRST_SEGMENT);
2378 0 : set_msg_importance(&sheader, get_real_importance(phdr));
2379 0 : set_msg_count(&sheader, mod(this->longMsgNo++));
2380 : /* Prepare header of first segment: */
2381 :
2382 0 : buf = buf_acquire(maxPacketSize);
2383 0 : if (!buf) {
2384 0 : return link_schedulePort(this, argv->origport);
2385 : }
2386 0 : memcpy(UD(buf)->data, &sheader, INTERNAL_HDR_SIZE);
2387 : /* msg = (tipc_msg_hdr_t*)(UD(buf)->data+INTERNAL_HDR_SIZE); */
2388 0 : hsize = get_hdr_size(phdr);
2389 : /* msg->msg_activity(ThreadManager::msg_activity()); */
2390 0 : this->statistics.sentSegmented++;
2391 0 : if (is_local_delivery(phdr) && is_direct_connect(phdr)) {
2392 0 : set_conn_seq_n(phdr, get_conn_seq_n(phdr) + 1);
2393 : }
2394 : dbg_msg("Sending long:\n");
2395 0 : memcpy(UD(buf)->data + INTERNAL_HDR_SIZE, phdr, hsize);
2396 :
2397 : /* Chop up message: */
2398 :
2399 : {
2400 0 : __u8 *segmentCrs = UD(buf)->data + INTERNAL_HDR_SIZE + hsize;
2401 0 : uint segmentRest = maxPacketSize - (hsize + INTERNAL_HDR_SIZE);
2402 0 : const __u8 *sectionCrs = 0;
2403 0 : uint sectionRest = 0;
2404 0 : int currSection = -1;
2405 0 : const TipcMsgSection *sectionSeq = argv->sectionSeq;
2406 :
2407 0 : do { /* For all sections */
2408 0 : uint oc;
2409 :
2410 0 : if (!sectionRest) {
2411 0 : currSection++;
2412 0 : sectionRest = sectionSeq[currSection].size;
2413 0 : sectionCrs = sectionSeq[currSection].data;
2414 : }
2415 :
2416 0 : oc = (sectionRest <
2417 : segmentRest) ? sectionRest : segmentRest;
2418 0 : memcpy(segmentCrs, sectionCrs, oc);
2419 0 : sectionCrs += oc;
2420 0 : sectionRest -= oc;
2421 0 : segmentCrs += oc;
2422 0 : segmentRest -= oc;
2423 0 : rest -= oc;
2424 :
2425 0 : if (!segmentRest) {
2426 : /* Send queued messages first, if any: */
2427 0 : if (this->media->busy_links)
2428 0 : tipc_continueInd(this->media);
2429 0 : this->statistics.sentSegments++;
2430 0 : link_sendBuf(this, buf);
2431 :
2432 0 : if (rest) {
2433 : /* Initiate new segment: */
2434 0 : uint segmentSize =
2435 : (rest >
2436 : segmentLimit) ? segmentLimit :
2437 0 : rest;
2438 : set_msg_size(&sheader,
2439 : segmentSize +
2440 0 : INTERNAL_HDR_SIZE);
2441 0 : set_msg_type(&sheader, SEGMENT);
2442 0 : buf = buf_acquire(maxPacketSize);
2443 : assert(buf); /* Only thing to do here */
2444 : memcpy(UD(buf)->data, &sheader,
2445 0 : INTERNAL_HDR_SIZE);
2446 0 : segmentCrs =
2447 : UD(buf)->data + INTERNAL_HDR_SIZE;
2448 0 : segmentRest = segmentSize;
2449 : }
2450 : }
2451 0 : }
2452 : while (rest > 0);
2453 : }
2454 : assert(rest <= 0);
2455 0 : return 0;
2456 : }
2457 :
2458 : void
2459 : link_sendLongBuf(Link * this, struct sk_buff *inBuf)
2460 34268 : {
2461 34268 : tipc_msg_hdr_t *inmsg = buf_msg(inBuf);
2462 34268 : tipc_msg_hdr_t sheader;
2463 34268 : uint insize = get_msg_size(inmsg);
2464 34268 : uint packetLimit = this->media->set.max_packet_sz;
2465 34268 : uint segmentLimit = packetLimit - INTERNAL_HDR_SIZE;
2466 :
2467 34332 : if (is_local_delivery(inmsg))
2468 0 : set_prev_node(inmsg, tipc_my_addr);
2469 :
2470 : /* Prepare reusable segment header: */
2471 :
2472 34268 : memset(&sheader, 0, INTERNAL_HDR_SIZE);
2473 68536 : set_msg_version(&sheader, MSG_VERSION_1);
2474 68536 : set_msg_user(&sheader, SEGMENTATION_MANAGER);
2475 68536 : set_msg_type(&sheader, FIRST_SEGMENT);
2476 68536 : set_hdr_size(&sheader, INTERNAL_HDR_SIZE);
2477 34268 : set_prev_node(&sheader, tipc_my_addr);
2478 137072 : set_link_selector(&sheader, get_link_selector(inmsg));
2479 137072 : set_msg_importance(&sheader, get_real_importance(inmsg));
2480 68536 : set_msg_count(&sheader, mod(this->longMsgNo++));
2481 34268 : this->statistics.sentSegmented++;
2482 : /* Chop up message: */
2483 : {
2484 34268 : __u8 *crs = UD(inBuf)->data;
2485 34268 : uint rest = insize;
2486 :
2487 34268 : while (rest > 0) {
2488 411216 : struct sk_buff *buf;
2489 411216 : uint segmentSize =
2490 411216 : (rest > segmentLimit) ? segmentLimit : rest;
2491 822432 : set_msg_size(&sheader, segmentSize + INTERNAL_HDR_SIZE);
2492 411216 : buf = buf_acquire(packetLimit);
2493 411216 : memcpy(UD(buf)->data, &sheader, INTERNAL_HDR_SIZE);
2494 : memcpy(UD(buf)->data + INTERNAL_HDR_SIZE, crs,
2495 411216 : segmentSize);
2496 :
2497 : /* Send queued messages first, if any: */
2498 411216 : if (this->media->busy_links)
2499 0 : tipc_continueInd(this->media);
2500 411216 : this->statistics.sentSegments++;
2501 411216 : link_sendBuf(this, buf);
2502 822432 : set_msg_type(&sheader, SEGMENT);
2503 411216 : rest -= segmentSize;
2504 411216 : crs += segmentSize;
2505 : }
2506 34268 : if (this->media->busy_links)
2507 0 : tipc_continueInd(this->media);
2508 34268 : buf_discard(inBuf);
2509 : }
2510 : }
2511 :
2512 : void
2513 : link_segmDataInd(Link * this, struct sk_buff *sbuf)
2514 411032 : {
2515 411032 : struct sk_buff *prev = 0;
2516 411032 : tipc_msg_hdr_t *smsg = buf_msg(sbuf);
2517 411032 : struct sk_buff *buf = this->desegm_buf;
2518 411032 : uint longMsgNo = get_msg_count(smsg);
2519 411032 : this->statistics.receivedSegments++;
2520 : /* Is there an incomplete message waiting for this segment? */
2521 411032 : while (buf && (get_msg_seq_n(buf_msg(buf)) != longMsgNo)) {
2522 :
2523 0 : prev = buf;
2524 0 : buf = UD(buf)->next;
2525 : }
2526 :
2527 34256 : if (!buf) { /* No match, this is the first segment of a new message */
2528 34256 : tipc_msg_hdr_t *imsg =
2529 68512 : (tipc_msg_hdr_t *) msg_data_start(buf_msg(sbuf));
2530 :
2531 : dbg("New long msg\n");
2532 : assert(get_msg_size(imsg) <=
2533 : TIPC_MAX_DATA_SIZE + LONG_HDR_SIZE);
2534 34256 : buf = buf_acquire(get_msg_size(imsg));
2535 34256 : UD(buf)->next = this->desegm_buf;
2536 34256 : this->desegm_buf = buf;
2537 102768 : memcpy(UD(buf)->data, (__u8 *) imsg, msg_data_size(smsg));
2538 :
2539 : /* Prepare buffer for subsequent segments: */
2540 68512 : set_msg_seq_n(buf_msg(buf), longMsgNo); /* Needed for later matching */
2541 34256 : UD(buf)->port =
2542 68512 : (TipcPort *) (UD(buf)->data + msg_data_size(smsg));
2543 34256 : this->statistics.receivedSegmented++;
2544 34256 : buf_discard(sbuf);
2545 376776 : return;
2546 : } else {
2547 753552 : uint dsize = msg_data_size(buf_msg(sbuf));
2548 376776 : __u8 *crs = (__u8 *) UD(buf)->port;
2549 376776 : uint received;
2550 376776 : tipc_msg_hdr_t *msg;
2551 :
2552 376776 : memcpy(crs, UD(sbuf)->data + INTERNAL_HDR_SIZE, dsize);
2553 376776 : crs += dsize;
2554 376776 : received = crs - UD(buf)->data;
2555 376776 : msg = buf_msg(buf);
2556 376776 : UD(buf)->port = (TipcPort *) crs;
2557 376776 : buf_discard(sbuf);
2558 :
2559 : /* Is message complete? */
2560 :
2561 376776 : if (received == get_msg_size(msg)) {
2562 34256 : if (prev)
2563 0 : UD(prev)->next = 0;
2564 : else
2565 34256 : this->desegm_buf = 0;
2566 :
2567 34256 : if (is_data_msg(msg)) {
2568 34256 : tipc_network_routemessage(buf);
2569 : } else {
2570 0 : link_specialMsgInd(this, buf);
2571 : }
2572 342520 : } else if (received > get_msg_size(msg)) {
2573 0 : warn("TIPC: Segment mismatch, received %u octets, expecting %u\n", received, get_msg_size(msg));
2574 0 : link_reset(this);
2575 : assert(0);
2576 : }
2577 : }
2578 : }
2579 :
2580 : #ifdef CONFIG_TIPC_DBG_BUF
2581 : void
2582 : link_dump(Link * this)
2583 : {
2584 : dbg_msg("Dumping log info for link to %x on %s:\n",
2585 : this->rep.addr, (this->media)->name);
2586 : }
2587 : #endif
2588 :
2589 : void
2590 : link_printSendQueue(Link * this)
2591 0 : {
2592 0 : if (this->nextOut) {
2593 0 : if (UD(this->nextOut)->data == (void *) 0x0000a3a3) {
2594 : dbg("nextOut %p invalid\n", this->nextOut);
2595 : }
2596 : }
2597 : dbg("Contents of send queue:\n");
2598 0 : if (this->firstOut) {
2599 0 : struct sk_buff *crs = this->firstOut;
2600 :
2601 0 : while (crs) {
2602 0 : if (UD(crs)->data == (void *) 0x0000a3a3) {
2603 : dbg("buffer %p invalid\n", crs);
2604 : } else {
2605 : dbg("next=%p:\n", crs);
2606 : }
2607 0 : crs = UD(crs)->next;
2608 : }
2609 : } else {
2610 0 : warn("Empty send queue\n");
2611 : }
2612 : }
2613 :
2614 : void
2615 : link_printRecQueue(Link * this)
2616 0 : {
2617 0 : struct sk_buff *crs;
2618 :
2619 0 : if (!this->oldestDeferredIn) {
2620 0 : info("Reception queue empty\n");
2621 0 : return;
2622 : }
2623 : dbg("Contents of Reception queue:\n");
2624 0 : crs = this->oldestDeferredIn;
2625 0 : while (crs) {
2626 0 : if (UD(crs)->data == (void *) 0x0000a3a3) {
2627 0 : warn("buffer %p invalid\n", crs);
2628 0 : return;
2629 : } else {
2630 : dbg("Msg %u ack flag: \n", get_msg_seq_n(buf_msg(crs)));
2631 : }
2632 0 : crs = UD(crs)->next;
2633 : }
2634 : }
2635 :
2636 : #ifdef CONFIG_TIPC_DBG_BUF
2637 : void
2638 : link_output(Link * this, tipc_dbg_buf_t * buf, const char *str)
2639 : {
2640 : debug_output(buf, str);
2641 : if (link_reset_reset(this) || link_reset_unknown(this))
2642 : return;
2643 : debug_output(buf, "Link %x(%s):", this->rep.addr, (this->media)->name);
2644 : debug_output(buf, ": NXO(%u):", mod(this->nxOutNo));
2645 : debug_output(buf, "NXI(%u):", this->nxInNo);
2646 : debug_output(buf, "SQUE");
2647 : if (this->firstOut) {
2648 : debug_output(buf, "[%u..",
2649 : get_msg_seq_n(buf_msg(this->firstOut)));
2650 : if (this->nextOut)
2651 : debug_output(buf, "%u..",
2652 : get_msg_seq_n(buf_msg(this->nextOut)));
2653 : debug_output(buf, "%u]", get_msg_seq_n(buf_msg(this->lastOut)),
2654 : this->outQueueSize);
2655 : if ((mod
2656 : (get_msg_seq_n(buf_msg(this->lastOut)) -
2657 : get_msg_seq_n(buf_msg(this->firstOut))) !=
2658 : (this->outQueueSize - 1))
2659 : || (UD(this->lastOut)->next != 0)) {
2660 : debug_output(buf, "Send queue inconsistency\n");
2661 : debug_output(buf, "firstOut= %x", this->firstOut);
2662 : debug_output(buf, "nextOut= %x", this->nextOut);
2663 : debug_output(buf, "lastOut= %x", this->lastOut);
2664 : link_printSendQueue(this);
2665 : }
2666 : } else
2667 : debug_output(buf, "[]");
2668 : debug_output(buf, "SQSIZ(%u)", this->outQueueSize);
2669 : if (this->oldestDeferredIn) {
2670 : uint o = get_msg_seq_n(buf_msg(this->oldestDeferredIn));
2671 : uint n = get_msg_seq_n(buf_msg(this->newestDeferredIn));
2672 :
2673 : debug_output(buf, ":RQUE[%u..%u]", o, n);
2674 : if (this->deferredInQueueSize != mod((n + 1) - o)) {
2675 : debug_output(buf, ":RQSIZ(%u)",
2676 : this->deferredInQueueSize);
2677 : }
2678 : }
2679 : if (link_working_unknown(this))
2680 : debug_output(buf, ":WU");
2681 : if (link_reset_reset(this))
2682 : debug_output(buf, ":RR");
2683 : if (link_reset_unknown(this))
2684 : debug_output(buf, ":RU");
2685 : if (link_working_working(this))
2686 : debug_output(buf, ":WW");
2687 : debug_output(buf, "\n");
2688 : }
2689 : #endif
2690 :
2691 : /* Some static functions can not use local log buffers: */
2692 : Link *
2693 : link_select(tipc_net_addr_t addr, uint selector)
2694 18 : {
2695 18 : tipc_net_addr_t router = 0;
2696 18 : Link *link = 0;
2697 18 : struct tipc_zone *zone;
2698 18 : struct tipc_cluster *cluster;
2699 18 : struct tipc_node *node;
2700 18 : uint zone_id = tipc_zone_id(addr);
2701 18 : uint cluster_id = tipc_cluster_id(addr);
2702 18 : uint node_id = tipc_node_id(addr);
2703 :
2704 : /* Look for direct link to destination node: */
2705 18 : zone = network.zones[zone_id];
2706 18 : if (!zone)
2707 : /* unknown zone, no links */
2708 0 : return 0;
2709 18 : cluster = zone->clusters[cluster_id];
2710 18 : if (!cluster) {
2711 0 : int i;
2712 :
2713 : /* Search for links to any other clusters within the zone */
2714 0 : for (i = 1; i < TIPC_CLUSTER_AMOUNT; i++) {
2715 0 : cluster = zone->clusters[i];
2716 0 : if (cluster)
2717 0 : router = tipc_cluster_selectrouter(cluster, selector);
2718 0 : if (router) {
2719 0 : link_selectLocalLink(router, selector, link);
2720 0 : return link;
2721 : }
2722 : }
2723 0 : return 0;
2724 : }
2725 18 : node = cluster->nodes[node_id];
2726 18 : if (node) {
2727 18 : if (tipc_node_activelinks(node))
2728 18 : return node->activeLinks[selector & 0x7];
2729 : /* Look for cluster local router with direct link to node: */
2730 0 : router = tipc_node_selectrouter(node, selector);
2731 0 : if (router) {
2732 0 : link_selectLocalLink(router, selector, link);
2733 0 : return link;
2734 : }
2735 : }
2736 : /* Cluster local system nodes *must* have direct links: */
2737 0 : if (!tipc_slave_addr(addr) && (tipc_zone_id(addr) == tipc_my_zone.id))
2738 0 : return 0;
2739 : /* Device nodes can only be accessed within own cluster via a
2740 : known router with direct link. If no router was found,give up: */
2741 0 : if (tipc_slave_addr(addr))
2742 0 : return 0;
2743 : /* Inter zone/cluster. Find any direct link to remote node: */
2744 0 : node = zone_selectremotenode(zone, addr & 0xfffff000, selector);
2745 0 : if (node)
2746 0 : return node->activeLinks[selector & 0x7];
2747 0 : return 0;
2748 : }
2749 :
2750 : /*
2751 : * calculation needed for each snprintf in
2752 : * tipc_LinkStatistics and an exit if the buffer is full.
2753 : */
2754 : #define BUF_UPDATE \
2755 : p += s; \
2756 : size -= s; \
2757 : if (size <= 0) \
2758 : goto tls_done;
2759 :
2760 : const char *
2761 : tipc_linkStatistics(const char *name, char *buf, int size)
2762 8 : {
2763 8 : Link *this = link_findByName(name);
2764 8 : uint profileTotal = 0;
2765 8 : uint i = 0;
2766 8 : int s;
2767 8 : char *p = buf;
2768 :
2769 8 : *buf = 0;
2770 8 : if (!this) {
2771 0 : strcpy(buf, "Link not found ");
2772 0 : goto tls_done;
2773 : }
2774 :
2775 8 : if (this->statistics.packLengthCounts) {
2776 2 : this->statistics.averagePackLength =
2777 : this->statistics.accuPackLength /
2778 : this->statistics.packLengthCounts;
2779 : } else
2780 6 : this->statistics.averagePackLength = 0;
2781 8 : this->statistics.sentPackets =
2782 : this->nxOutNo - this->statistics.resetOutPackCount;
2783 :
2784 8 : s = snprintf(p, size, "State of link %s:\n", this->rep.name);
2785 8 : BUF_UPDATE;
2786 8 : s = snprintf(p, size, "Link is %s\n", link_state(this));
2787 8 : BUF_UPDATE;
2788 8 : s = snprintf(p, size, "Tolerance is %u [ms]\n", this->tolerance);
2789 8 : BUF_UPDATE;
2790 8 : s = snprintf(p, size, "Window limit is %u packets\n",
2791 : this->windowLimit);
2792 8 : BUF_UPDATE;
2793 8 : s = snprintf(p, size, "Priority is %u\n\n", this->priority);
2794 8 : BUF_UPDATE;
2795 8 : s = snprintf(p, size, "Statistics:\n");
2796 8 : BUF_UPDATE;
2797 8 : s = snprintf(p, size, "----------\n");
2798 8 : BUF_UPDATE;
2799 8 : s = snprintf(p, size, "Sent packets: %u\n",
2800 : this->statistics.sentPackets);
2801 8 : BUF_UPDATE;
2802 8 : s = snprintf(p, size, "Received packets: %u\n",
2803 : this->statistics.receivedPackets);
2804 8 : BUF_UPDATE;
2805 8 : s = snprintf(p, size, "Sent publications: %u\n",
2806 : this->statistics.sentPublications);
2807 8 : BUF_UPDATE;
2808 8 : s = snprintf(p, size, "Received publications: %u\n",
2809 : this->statistics.receivedPublications);
2810 8 : BUF_UPDATE;
2811 8 : s = snprintf(p, size, "Sent withdrawals: %u\n",
2812 : this->statistics.sentWithdrawals);
2813 8 : BUF_UPDATE;
2814 8 : s = snprintf(p, size, "Received withdrawals: %u\n",
2815 : this->statistics.receivedWithdrawals);
2816 8 : BUF_UPDATE;
2817 8 : s = snprintf(p, size, "Sent bundles: %u\n",
2818 : this->statistics.sentBundles);
2819 8 : BUF_UPDATE;
2820 8 : s = snprintf(p, size, "Sent bundled: %u\n",
2821 : this->statistics.sentBundled);
2822 8 : BUF_UPDATE;
2823 8 : s = snprintf(p, size, "Received bundles: %u\n",
2824 : this->statistics.receivedBundles);
2825 8 : BUF_UPDATE;
2826 8 : s = snprintf(p, size, "Received bundled: %u\n",
2827 : this->statistics.receivedBundled);
2828 8 : BUF_UPDATE;
2829 8 : s = snprintf(p, size, "Sent segmented: %u\n",
2830 : this->statistics.sentSegmented);
2831 8 : BUF_UPDATE;
2832 8 : s = snprintf(p, size, "Sent segments: %u\n",
2833 : this->statistics.sentSegments);
2834 8 : BUF_UPDATE;
2835 8 : s = snprintf(p, size, "Received segmented: %u\n",
2836 : this->statistics.receivedSegmented);
2837 8 : BUF_UPDATE;
2838 8 : s = snprintf(p, size, "Received segments: %u\n",
2839 : this->statistics.receivedSegments);
2840 8 : BUF_UPDATE;
2841 8 : s = snprintf(p, size, "Average packet length: %u [octets] \n",
2842 : this->statistics.averagePackLength);
2843 8 : BUF_UPDATE;
2844 8 : s = snprintf(p, size, "Sent Messages Profile:\n");
2845 8 : BUF_UPDATE;
2846 64 : for (i = 0; i <= 6; i++) {
2847 56 : profileTotal += this->statistics.msgLengthProfile[i];
2848 : }
2849 8 : if (!profileTotal)
2850 8 : profileTotal = 1;
2851 8 : s = snprintf(p, size, " 0-64 octets: %02u [%%] \n",
2852 : (this->statistics.msgLengthProfile[0] * 100) /
2853 : profileTotal);
2854 8 : BUF_UPDATE;
2855 8 : s = snprintf(p, size, " 65-256 octets: %02u [%%] \n",
2856 : (this->statistics.msgLengthProfile[1] * 100) /
2857 : profileTotal);
2858 8 : BUF_UPDATE;
2859 8 : s = snprintf(p, size, " 257-1024 octets: %02u [%%] \n",
2860 : (this->statistics.msgLengthProfile[2] * 100) /
2861 : profileTotal);
2862 8 : BUF_UPDATE;
2863 8 : s = snprintf(p, size, " 1025-4096 octets: %02u [%%] \n",
2864 : (this->statistics.msgLengthProfile[3] * 100) /
2865 : profileTotal);
2866 8 : BUF_UPDATE;
2867 8 : s = snprintf(p, size, " 4097-16354 octets: %02u [%%] \n",
2868 : (this->statistics.msgLengthProfile[4] * 100) /
2869 : profileTotal);
2870 8 : BUF_UPDATE;
2871 8 : s = snprintf(p, size, "16355-32768 octets: %02u [%%] \n",
2872 : (this->statistics.msgLengthProfile[5] * 100) /
2873 : profileTotal);
2874 8 : BUF_UPDATE;
2875 8 : s = snprintf(p, size, "32769-65408 octets: %02u [%%] \n",
2876 : (this->statistics.msgLengthProfile[6] * 100) /
2877 : profileTotal);
2878 :
2879 8 : BUF_UPDATE;
2880 8 : s = snprintf(p, size, "Link Behaviour:\n");
2881 8 : BUF_UPDATE;
2882 8 : s = snprintf(p, size, "---------------\n");
2883 8 : BUF_UPDATE;
2884 8 : s = snprintf(p, size, "Sent states: %u\n",
2885 : this->statistics.sentStates);
2886 8 : BUF_UPDATE;
2887 8 : s = snprintf(p, size, "Received states: %u\n",
2888 : this->statistics.receivedStates);
2889 8 : BUF_UPDATE;
2890 8 : s = snprintf(p, size, "Sent probes: %u\n",
2891 : this->statistics.sentProbes);
2892 8 : BUF_UPDATE;
2893 8 : s = snprintf(p, size, "Received probes: %u\n",
2894 : this->statistics.receivedProbes);
2895 8 : BUF_UPDATE;
2896 8 : s = snprintf(p, size, "Sent explicit acks: %u\n",
2897 : this->statistics.sentExplicitAcks);
2898 8 : BUF_UPDATE;
2899 8 : s = snprintf(p, size, "Sent deadlock acks: %u\n",
2900 : this->statistics.sentDeadlockAcks);
2901 8 : BUF_UPDATE;
2902 8 : s = snprintf(p, size, "Sent nacks: %u\n",
2903 : this->statistics.sentNacks);
2904 8 : BUF_UPDATE;
2905 8 : s = snprintf(p, size, "Received nacks: %u\n",
2906 : this->statistics.receivedNacks);
2907 8 : BUF_UPDATE;
2908 8 : s = snprintf(p, size, "Retransmitted: %u\n",
2909 : this->statistics.retransmitted);
2910 8 : BUF_UPDATE;
2911 8 : s = snprintf(p, size, "Pushed: %u\n",
2912 : this->statistics.pushed);
2913 8 : BUF_UPDATE;
2914 8 : s = snprintf(p, size, "Deferred Sendings: %u\n",
2915 : this->statistics.deferredSendings);
2916 8 : BUF_UPDATE;
2917 8 : s = snprintf(p, size, "Deferred Receptions: %u\n",
2918 : this->statistics.deferredReceptions);
2919 8 : BUF_UPDATE;
2920 8 : s = snprintf(p, size, "Incoming duplicates: %u\n",
2921 : this->statistics.duplicates);
2922 8 : BUF_UPDATE;
2923 8 : s = snprintf(p, size, "Window overflows: %u\n",
2924 : this->statistics.windowOverflows);
2925 8 : BUF_UPDATE;
2926 8 : s = snprintf(p, size, "Max send queue size: %u\n",
2927 : this->statistics.maxQueueSize);
2928 8 : BUF_UPDATE;
2929 8 : s = snprintf(p, size, "Average send queue size: %u\n",
2930 : this->statistics.queueSizeCounts ? (this->statistics.
2931 : accuQueueSize /
2932 : this->statistics.
2933 : queueSizeCounts) : 0);
2934 : tls_done:
2935 8 : return buf;
2936 : }
2937 :
2938 : uint
2939 : tipc_resetLinkStatistics(const char *name)
2940 0 : {
2941 0 : Link *this = link_findByName(name);
2942 :
2943 0 : if (!this)
2944 0 : return 1;
2945 : dbg("Resetting statistics for %s\n", name);
2946 0 : link_resetStatistics(this);
2947 0 : return 0;
2948 : }
2949 :
2950 : uint
2951 : tipc_blockLink(const char *name)
2952 0 : {
2953 0 : Link *this = link_findByName(name);
2954 :
2955 0 : if (!this)
2956 0 : return 1;
2957 0 : link_reset(this);
2958 0 : this->expectedMsgCount = BLOCKED;
2959 0 : return 0;
2960 : }
2961 :
2962 : uint
2963 : tipc_unblockLink(const char *name)
2964 0 : {
2965 0 : Link *this = link_findByName(name);
2966 :
2967 0 : if (!this)
2968 0 : return 1;
2969 0 : this->expectedMsgCount = 0;
2970 0 : return 0;
2971 : }
2972 :
2973 : const struct tipc_media_addr *
2974 : tipc_getPeerAddress(const char *name)
2975 0 : {
2976 0 : Link *this = link_findByName(name);
2977 :
2978 0 : if (!this)
2979 0 : return 0;
2980 0 : return (const struct tipc_media_addr *) &this->rep.mediaAddr;
2981 : }
2982 :
2983 : void
2984 : link_setTolerance(Link * this, uint tolerance)
2985 4 : {
2986 4 : if (!tolerance)
2987 4 : return;
2988 4 : this->tolerance = tolerance;
2989 4 : this->continuityInterval =
2990 : ((tolerance / 4) > 500) ? 500 : tolerance / 4;
2991 4 : this->abortLimit = tolerance / (this->continuityInterval / 4);
2992 : }
2993 :
2994 : uint
2995 : tipc_setLinkTolerance(const tipc_configure_link_argv * argv)
2996 0 : {
2997 0 : Link *this = link_findByName((const char *) &argv->name);
2998 :
2999 0 : if (!this)
3000 0 : return 1;
3001 0 : if ((argv->value < 50) || (argv->value > 30000))
3002 0 : return 1;
3003 0 : link_setTolerance(this, argv->value);
3004 0 : link_protocolDataReq(this, STATE_MSG, 0, 0, argv->value, 0);
3005 0 : return 0;
3006 : }
3007 :
3008 : uint
3009 : tipc_setLinkPriority(const tipc_configure_link_argv * argv)
3010 0 : {
3011 0 : Link *this = link_findByName((const char *) &argv->name);
3012 :
3013 0 : if (!this)
3014 0 : return 1;
3015 0 : if ((argv->value < 1) || (argv->value > 31))
3016 0 : return 1;
3017 0 : this->priority = argv->value;
3018 0 : link_protocolDataReq(this, STATE_MSG, 0, 0, 0, argv->value);
3019 0 : return 0;
3020 : }
3021 :
3022 : uint
3023 : tipc_setLinkWindow(const tipc_configure_link_argv * argv)
3024 0 : {
3025 0 : Link *this = link_findByName((const char *) &argv->name);
3026 :
3027 0 : if (!this)
3028 0 : return 1;
3029 0 : if (argv->value > 200)
3030 0 : return 1;
3031 0 : this->windowLimit = argv->value;
3032 0 : return 0;
3033 : }
3034 :
3035 : uint
3036 : tipc_removeLink(const char *name)
3037 0 : {
3038 0 : Link *this = link_findByName(name);
3039 :
3040 0 : if (this)
3041 0 : link_delete(this);
3042 0 : return 0;
3043 : }
3044 :
3045 : void
3046 : link_stop(Link * this)
3047 0 : {
3048 0 : struct sk_buff *buf;
3049 :
3050 0 : link_releaseQuarantine(this);
3051 :
3052 0 : buf = this->oldestDeferredIn;
3053 0 : while (buf) {
3054 0 : struct sk_buff *next = UD(buf)->next;
3055 :
3056 0 : buf_discard(buf);
3057 0 : buf = next;
3058 : }
3059 :
3060 0 : buf = this->firstOut;
3061 0 : while (buf) {
3062 0 : struct sk_buff *next = UD(buf)->next;
3063 :
3064 0 : if (!skb_shared(buf))
3065 0 : buf_discard(buf);
3066 0 : buf = next;
3067 : }
3068 0 : link_segmReset(this);
3069 0 : buf = this->protocolBuf;
3070 : #ifdef CONFIG_TIPC_DBG_BUF
3071 : dbg("Releasing protocol buf: %p\n", buf);
3072 : #endif
3073 0 : if (buf && (!skb_shared(buf)))
3074 0 : buf_discard(buf);
3075 0 : link_cancelTimer(this);
3076 : }
|