LTP GCOV extension - code coverage report
Current view: directory - net/tipc - link.c
Test: tipc.info
Date: 2003-08-07 Instrumented lines: 1449
Code covered: 45.3 % Executed lines: 657

       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                 : }

Generated by: LTP GCOV extension version 1.1