Exemple #1
0
        /* <pre>
         *       5.2.1.  INIT Received in COOKIE-WAIT or COOKIE-ECHOED State (Item B)
         *
         *       This usually indicates an initialization collision, i.e., each
         *       endpoint is attempting, at about the same time, to establish an
         *       association with the other endpoint.
         *
         *       Upon receipt of an INIT in the COOKIE-WAIT state, an endpoint MUST
         *       respond with an INIT ACK using the same parameters it sent in its
         *       original INIT chunk (including its Initiate Tag, unchanged).  When
         *       responding, the endpoint MUST send the INIT ACK back to the same
         *       address that the original INIT (sent by this endpoint) was sent.
         *
         *       Upon receipt of an INIT in the COOKIE-ECHOED state, an endpoint MUST
         *       respond with an INIT ACK using the same parameters it sent in its
         *       original INIT chunk (including its Initiate Tag, unchanged), provided
         *       that no NEW address has been added to the forming association.  If
         *       the INIT message indicates that a new address has been added to the
         *       association, then the entire INIT MUST be discarded, and NO changes
         *       should be made to the existing association.  An ABORT SHOULD be sent
         *       in response that MAY include the error 'Restart of an association
         *       with new addresses'.  The error SHOULD list the addresses that were
         *       added to the restarting association.
         *
         *       When responding in either state (COOKIE-WAIT or COOKIE-ECHOED) with
         *       an INIT ACK, the original parameters are combined with those from the
         *       newly received INIT chunk.  The endpoint shall also generate a State
         *       Cookie with the INIT ACK.  The endpoint uses the parameters sent in
         *       its INIT to calculate the State Cookie.
         *
         *       After that, the endpoint MUST NOT change its state, the T1-init timer
         *       shall be left running, and the corresponding TCB MUST NOT be
         *       destroyed.  The normal procedures for handling State Cookies when a
         *       TCB exists will resolve the duplicate INITs to a single association.
         *
         *       For an endpoint that is in the COOKIE-ECHOED state, it MUST populate
         *       its Tie-Tags within both the association TCB and inside the State
         *       Cookie (see Section 5.2.2 for a description of the Tie-Tags).
         *       </pre>
         */
        public virtual Chunk[] inboundInit(InitChunk init)
        {
            Chunk[] reply = null;
            _peerVerTag = init.getInitiateTag();
            _winCredit  = init.getAdRecWinCredit();
            _farTSN     = (uint)(init.getInitialTSN() - 1);

            _maxOutStreams = Math.Min(init.getNumInStreams(), MAXSTREAMS);
            _maxInStreams  = Math.Min(init.getNumOutStreams(), MAXSTREAMS);
            InitAckChunk iac = new InitAckChunk();

            iac.setAdRecWinCredit(MAXBUFF);
            iac.setNumInStreams(_maxInStreams);
            iac.setNumOutStreams(_maxOutStreams);
            iac.setInitialTSN(_nearTSN);
            iac.setInitiateTag(_myVerTag);
            CookieHolder cookie = new CookieHolder();

            cookie.cookieData = new byte[Association.COOKIESIZE];
            cookie.cookieTime = TimeExtension.CurrentTimeMillis();
            _random.NextBytes(cookie.cookieData);
            iac.setCookie(cookie.cookieData);
            _cookies.Add(cookie);

            byte[] fse = init.getFarSupportedExtensions();
            if (fse != null)
            {
                iac.setSupportedExtensions(this.getUnionSupportedExtensions(fse));
            }
            reply    = new Chunk[1];
            reply[0] = iac;
            //logger.LogDebug("SCTP received INIT:" + init.ToString());
            //logger.LogDebug("Replying with init-ack :" + iac.ToString());
            return(reply);
        }
Exemple #2
0
        protected virtual Chunk[] iackDeal(InitAckChunk iack)
        {
            iack.getAdRecWinCredit();
            iack.getInitialTSN();
            iack.getNumInStreams();
            iack.getNumOutStreams();

            /*
             *           NOTE: TO DO - this is a protocol violation - this should be done with
             *           multiple TCBS and set in cookie echo
             *           NOT HERE
             */

            _peerVerTag    = iack.getInitiateTag();
            _winCredit     = iack.getAdRecWinCredit();
            _farTSN        = iack.getInitialTSN() - 1;
            _maxOutStreams = Math.Min(iack.getNumInStreams(), MAXSTREAMS);
            _maxInStreams  = Math.Min(iack.getNumOutStreams(), MAXSTREAMS);

            iack.getSupportedExtensions(_supportedExtensions);
            byte[]          data = iack.getCookie();
            CookieEchoChunk ce   = new CookieEchoChunk();

            ce.setCookieData(data);
            Chunk[] reply = new Chunk[1] {
                ce
            };
            this._state = State.COOKIEECHOED;
            return(reply);
        }
Exemple #3
0
        /*
         * If the T1-init timer expires at "A" after the INIT or COOKIE ECHO
         * chunks are sent, the same INIT or COOKIE ECHO chunk with the same
         * Initiate Tag (i.e., Tag_A) or State Cookie shall be retransmitted and
         * the timer restarted.  This shall be repeated Max.Init.Retransmits
         * times before "A" considers "Z" unreachable and reports the failure to
         * its upper layer (and thus the association enters the CLOSED state).
         *
         * When retransmitting the INIT, the endpoint MUST follow the rules
         * defined in Section 6.3 to determine the proper timer value.
         */

        protected override Chunk[] iackDeal(InitAckChunk iack)
        {
            Chunk[] ret = base.iackDeal(iack);
            _stashCookieEcho = ret;
            return(ret);
        }
Exemple #4
0
        /**
         *
         * @param c - Chunk to be processed
         * @return valid - false if the remaining chunks of the packet should be
         * ignored.
         * @throws IOException
         * @throws SctpPacketFormatException
         */
        private bool deal(Chunk c, List <Chunk> replies)
        {
            ChunkType ty       = c.getType();
            bool      ret      = true;
            State     oldState = _state;

            Chunk[] reply = null;
            switch (ty)
            {
            case ChunkType.INIT:
                if (acceptableStateForInboundInit())
                {
                    InitChunk init = (InitChunk)c;
                    reply = inboundInit(init);
                }
                else
                {
                    // logger.LogDebug("Got an INIT when state was " + _state.ToString() + " - ignoring it for now ");
                }
                break;

            case ChunkType.INITACK:
                //logger.LogDebug("got initack " + c.ToString());
                if (_state == State.COOKIEWAIT)
                {
                    InitAckChunk iack = (InitAckChunk)c;
                    reply = iackDeal(iack);
                }
                else
                {
                    //logger.LogDebug("Got an INITACK when not waiting for it - ignoring it");
                }
                break;

            case ChunkType.COOKIE_ECHO:
                // logger.LogDebug("got cookie echo " + c.ToString());
                reply = cookieEchoDeal((CookieEchoChunk)c);
                if (reply.Length > 0)
                {
                    ret = !typeof(ErrorChunk).IsAssignableFrom(reply[0].GetType());     // ignore any following data chunk.
                }
                break;

            case ChunkType.COOKIE_ACK:
                //logger.LogDebug("got cookie ack " + c.ToString());
                if (_state == State.COOKIEECHOED)
                {
                    _state = State.ESTABLISHED;
                }
                break;

            case ChunkType.DATA:
                //logger.LogDebug("got data " + c.ToString());
                reply = dataDeal((DataChunk)c);
                break;

            case ChunkType.ABORT:
                // no reply we should just bail I think.
                _rcv = null;
                _transp.Close();
                break;

            case ChunkType.HEARTBEAT:
                reply = ((HeartBeatChunk)c).mkReply();
                break;

            case ChunkType.SACK:
                //logger.LogDebug("got tsak for TSN " + ((SackChunk)c).getCumuTSNAck());
                reply = sackDeal((SackChunk)c);
                // fix the outbound list here
                break;

            case ChunkType.RE_CONFIG:
                reply = reconfigState.deal((ReConfigChunk)c);
                break;

            case ChunkType.ERROR:
                logger.LogWarning($"SCTP error chunk received.");
                foreach (var vparam in c._varList)
                {
                    if (vparam is KnownError)
                    {
                        var knownErr = vparam as KnownError;
                        logger.LogWarning($"{knownErr.getName()}, {knownErr}");
                    }
                }
                break;
            }
            if (reply != null)
            {
                foreach (Chunk r in reply)
                {
                    replies.Add(r);
                }
                // theoretically could be multiple DATA in a single packet -
                // we'd send multiple SACKs in reply - ToDo fix that
            }
            if ((_state == State.ESTABLISHED) && (oldState != State.ESTABLISHED))
            {
                if (null != _al)
                {
                    _al.onAssociated(this);
                }
                reconfigState = new ReconfigState(this, _farTSN);
            }
            if ((oldState == State.ESTABLISHED) && (_state != State.ESTABLISHED))
            {
                if (null != _al)
                {
                    _al.onDisAssociated(this);
                }
            }
            return(ret);
        }
Exemple #5
0
        public static Chunk mkChunk(ByteBuffer pkt)
        {
            Chunk ret = null;

            if (pkt.remaining() >= 4)
            {
                ChunkType type   = (ChunkType)pkt.GetByte();
                byte      flags  = pkt.GetByte();
                int       length = pkt.GetUShort();
                switch (type)
                {
                case ChunkType.DATA:
                    ret = new DataChunk(flags, length, pkt);
                    break;

                case ChunkType.INIT:
                    ret = new InitChunk(type, flags, length, pkt);
                    break;

                case ChunkType.SACK:
                    ret = new SackChunk(type, flags, length, pkt);
                    break;

                case ChunkType.INITACK:
                    ret = new InitAckChunk(type, flags, length, pkt);
                    break;

                case ChunkType.COOKIE_ECHO:
                    ret = new CookieEchoChunk(type, flags, length, pkt);
                    break;

                case ChunkType.COOKIE_ACK:
                    ret = new CookieAckChunk(type, flags, length, pkt);
                    break;

                case ChunkType.ABORT:
                    ret = new AbortChunk(type, flags, length, pkt);
                    break;

                case ChunkType.HEARTBEAT:
                    ret = new HeartBeatChunk(type, flags, length, pkt);
                    break;

                case ChunkType.RE_CONFIG:
                    ret = new ReConfigChunk(type, flags, length, pkt);
                    break;

                case ChunkType.ERROR:
                    ret = new ErrorChunk(type, flags, length, pkt);
                    break;

                default:
                    logger.LogWarning($"SCTP unknown chunk type received {type}.");
                    ret = new FailChunk(type, flags, length, pkt);
                    break;
                }
                if (ret != null)
                {
                    if (pkt.hasRemaining())
                    {
                        int mod = ret.getLength() % 4;
                        if (mod != 0)
                        {
                            for (int pad = mod; pad < 4; pad++)
                            {
                                pkt.GetByte();
                            }
                        }
                    }
                }
            }
            return(ret);
        }