예제 #1
0
    def recvSCCRQ(self, pkt):
        """Receive SCCRQ."""
        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.SCCRQMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                self.fsm.recvBadSCCRQ()
                return L2tpv3ControlPacket.L2tpv3StopCCN(
                    self, 2, 4, "Avp cannot handled correctly")
        sccrpAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
            L2tpv3RFC3931AVPs.ControlMessageAVP.SCCRP)
        recvWinSize = ReceiveWinSize(
            L2tpv3GlobalSettings.L2tpv3GlobalSettings.ReceiveWindowSize)

        sccrp = L2tpv3ControlPacket.L2tpv3ControlPacket(
            self.remoteConnID, 0, 0, (sccrpAvp, recvWinSize))

        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                # We got a bad SCCRQ, we should send a CDN
                if not avp.handleAvp(pkt, sccrp):
                    self.fsm.recvBadSCCRQ()
                    return L2tpv3ControlPacket.L2tpv3StopCCN(
                        self, 2, 4, "Avp cannot handled correctly")
        self.fsm.recvGoodSCCRQ()
        return sccrp
예제 #2
0
    def ReceiveICCN(self, pkt):
        """Receive a ICCN packet from the connection. Will process the AVPs.

        :param pkt: THe decoded l2tp control packet.
        :return: a ICCN response packet or None

        """
        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.connection.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.ICCNMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                self.fsm.recvBadICCN()
                return L2tpv3ControlPacket.L2tpv3CDN(
                    self, 2, 4, "Avp cannot be handled correctly")

        self.logger.debug("L2Tp session[%d, %d] receive a ICCN message",
                          self.localSessionId, self.remoteSessionId)

        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                # We got a bad ICCN, we should send a CDN
                if not avp.handleAvp(pkt, None):
                    self.fsm.recvBadICCN()
                    return L2tpv3ControlPacket.L2tpv3CDN(
                        self, 2, 4, "Avp cannot be handled correctly")
        self.logger.debug("Session[%d, %d] got a good ICCN, send it to fsm.",
                          self.localSessionId, self.remoteSessionId)
        self.fsm.recvGoodICCN()
        # We need to send the ZLB.
        ackpkt = L2tpv3ControlPacket.L2tpv3ACK(
            connID=self.connection.remoteConnID)
        return ackpkt
예제 #3
0
    def ReceiveSLI(self, pkt):
        """Receive a SLI packet, handle the AVP.

        :param pkt:
        :return:

        """
        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.connection.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.SLIMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                return L2tpv3ControlPacket.L2tpv3CDN(
                    self, 2, 4, "Cannot handle AVP in SLI message")

        self.logger.debug("L2Tp Session[%d, %d] receive a SLI message",
                          self.localSessionId, self.remoteSessionId)
        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                if not avp.handleAvp(pkt, None):
                    return L2tpv3ControlPacket.L2tpv3CDN(
                        self, 2, 4, "Cannot handle AVP in SLI message")

        return None
예제 #4
0
    def _findSession(self, pkt):
        # Find the remote Session
        remoteSessid = 0
        localSessId = 0
        for avp in pkt.avps:
            if isinstance(avp, L2tpv3RFC3931AVPs.LocalSessionID):
                remoteSessid = avp.sessionID
            elif isinstance(avp, L2tpv3RFC3931AVPs.RemoteSessionID):
                localSessId = avp.sessionID

        if not remoteSessid and not localSessId:
            self.logger.warn(
                "Got a packet but no local/remote session ID is set, we cannot send "
                "rsp since we don't know the session ID")
            return None

        # Try to find the session, this is the case sender or some error packet
        # happens
        session1 = self.findSessionByRemoteSessionID(remoteSessid)
        session2 = self.findSessionByLocalSessionID(localSessId)
        if session1 is None and session2 is None:
            # generate a fake session for it, for send the CDN
            session = L2tpv3Session.L2tpv3Session(randint(1, 0xFFFFFFFF),
                                                  remoteSessid, 'receive',
                                                  self)
            cdn = L2tpv3ControlPacket.L2tpv3CDN(
                session, 2, 5, "Cannot find the session in local runtime DB")
            self.transport.SendPacket(cdn)
            return None

        return session1 if session1 else session2
예제 #5
0
    def LocalRequest(self):
        """Local request will trigger the session to send a ICRQ to remote,
        currently, this function is just for simulator usage.

        :return: None

        """
        self.logger.debug(
            "Got a local request to setup the session, will send a ICRQ to remote"
        )

        if isinstance(self.fsm, L2tpv3Fsm.L2tpv3SessionRecipientFsm):
            self.logger.warn(
                "Recipient does not support the local request, do nothing.")
            return

        if self.fsm.current == L2tpv3Fsm.L2tpv3SessionSenderFsm.StateIdle:
            msgAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
                L2tpv3RFC3931AVPs.ControlMessageAVP.ICRQ)
            localSessionId = L2tpv3RFC3931AVPs.LocalSessionID(
                self.localSessionId)
            remoteSessionId = L2tpv3RFC3931AVPs.RemoteSessionID(
                self.remoteSessionId)
            remote_end_id = L2tpv3RFC3931AVPs.RemoteEndID(
                (((0, 3, 0), 0), ((0, 3, 1), 1)))
            DepiL2SpecificSublayerSubtype = L2tpv3CableLabsAvps.DepiL2SpecificSublayerSubtype(
                3)

            icrq = L2tpv3ControlPacket.L2tpv3ControlPacket(
                self.connection.remoteConnID,
                avps=(msgAvp, localSessionId, remoteSessionId, remote_end_id,
                      DepiL2SpecificSublayerSubtype))
            self.connection.transport.SendPacket(icrq)

        self.fsm.localRequest()
예제 #6
0
    def recvFSQ(self, pkt):
        """Receive a FSQ packet.

        :param pkt: Decoded control packet.
        :return: FSR.

        """
        self.logger.debug("Receive a FSQ message from remote")
        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.FSQMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                return

        fsrAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
            L2tpv3RFC3931AVPs.ControlMessageAVP.FSR)
        fsr = L2tpv3ControlPacket.L2tpv3ControlPacket(self.remoteConnID, 0, 0,
                                                      (fsrAvp, ))

        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                avp.handleAvp(pkt, fsr)

        return fsr
예제 #7
0
    def CloseConnection(self):
        """Clean up the resource, including the following parts:

        * sessions
        * transport
        * fsm

        :return: none

        """
        if self.connection_status == L2tpConnection.CREATED:
            keys = self.sessions.keys()
            for sessionId in keys:
                session = self.sessions[sessionId]
                if hasattr(session.fsm.fsm, 'transition'):
                    delattr(session.fsm.fsm, 'transition')
                    self.logger.debug("The session %d fsm is undergoing!!",
                                      sessionId)
                session.CloseSession()
                self.removeSession(session)
            # Send a StopCCN
            self.transport.SendPacket(
                L2tpv3ControlPacket.L2tpv3StopCCN(self, 1, 0,
                                                  "Close the connection"),
                None)

            # process the transport
            self.transport.CloseTransport()

            # remove it from the global connection DB
            self.ConnectionDb.pop(
                (self.remoteAddr, self.localAddr, self.localConnID))
            self.connection_status = L2tpConnection.CLOSED
예제 #8
0
    def recvHELLO(self, pkt):
        """Receive a HELLO packet.

        :param pkt: Decoded control packet.
        :return: None.

        """
        self.logger.debug(
            "Receive a Hello message from remote, send a ZLB to it")
        return L2tpv3ControlPacket.L2tpv3ZLB(self.remoteConnID)
예제 #9
0
    def recvSCCRP(self, pkt):
        """On openRPD, we will behave as an recipient, so we will not receive
        SCCRP in normal case.

        :param pkt:
        :return:

        """
        self.logger.debug("Receive a SCCRP packet")

        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.SCCRPMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                self.fsm.recvBadSCCRP()
                return L2tpv3ControlPacket.L2tpv3StopCCN(
                    self, 2, 4, "Avp cannot handled correctly")
        # Get the localAssignedID from the SCCRP
        remoteConnID = 0
        for avp in pkt.avps:
            if isinstance(avp, L2tpv3RFC3931AVPs.AssignedControlConnectionID):
                remoteConnID = avp.connectionID

        self.remoteConnID = remoteConnID
        scccnAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
            L2tpv3RFC3931AVPs.ControlMessageAVP.SCCCN)
        scccn = L2tpv3ControlPacket.L2tpv3ControlPacket(
            self.remoteConnID, 0, 0, (scccnAvp, ))

        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                # We got a bad ICRQ, we should send a CDN
                if not avp.handleAvp(pkt, scccn):
                    self.fsm.recvBadSCCRP()
                    return L2tpv3ControlPacket.L2tpv3StopCCN(
                        self, 2, 4, "Avp cannot handled correctly")

        self.fsm.recvGoodSCCRP()
        return scccn
예제 #10
0
    def localRequest(self, addr):
        # send a SCCRQ to remote

        msgAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
            L2tpv3RFC3931AVPs.ControlMessageAVP.SCCRQ)
        assignedAvp = L2tpv3RFC3931AVPs.AssignedControlConnectionID(
            self.localConnID)
        sccrq = L2tpv3ControlPacket.L2tpv3ControlPacket(0,
                                                        avps=(msgAvp,
                                                              assignedAvp))
        self.transport.SendPacket(sccrq, (addr, 0))

        self.fsm.localRequest()
예제 #11
0
    def recvStopCCN(self, pkt):
        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.StopCCNMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                return

        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                avp.handleAvp(pkt, None)
        self.fsm.recvStopCCN()
        ackpkt = L2tpv3ControlPacket.L2tpv3ACK(connID=self.remoteConnID)
        return ackpkt
예제 #12
0
    def _handleSessionQuery(self, msg):
        self.logger.debug("Handling the session query message, msg = %s" % msg)
        retMsg = l2tpMsg.L2tpCommandRsp()
        retMsg.rsp = l2tpMsg.SUCCESS
        retMsg.retMsg = "Success"

        if not msg.HasField("sess"):
            retMsg.rsp = l2tpMsg.FAILURE
            retMsg.retMsg = "Cannot find the session parameter in session query msg"
            return retMsg

        sess = msg.sess
        conn = sess.conn
        remoteAddr = conn.remoteAddr
        localAddr = conn.localAddr
        connID = conn.connectionID
        localSessionId = sess.localSessionID

        connectionDb = L2tpv3Connection.L2tpConnection.ConnectionDb
        if not (remoteAddr, localAddr, connID) in connectionDb:
            retMsg.rsp = l2tpMsg.FAILURE
            retMsg.retMsg = "Cannot find the connection in local connection DB"
            return retMsg
        connection = connectionDb[(remoteAddr, localAddr, connID)]

        if localSessionId not in connection.sessions:
            retMsg.rsp = l2tpMsg.FAILURE
            retMsg.retMsg = "Cannot find the session in local connection DB"
            return retMsg

        session = connection.sessions[localSessionId]

        retMsg.sessInfo.connectionID = connID
        retMsg.sessInfo.currentState = session.fsm.current
        retMsg.sessInfo.localSessionID = session.localSessionId
        retMsg.sessInfo.remoteSessionID = session.remoteSessionId
        retMsg.sessInfo.sessionType = L2tpHalClient.sessionSubTypeStr[
            session.session_l2Sublayer]
        retMsg.sessInfo.lastchangetime = datetime.datetime.fromtimestamp(session.lastchangetime).\
            strftime("%H:%M:%S %Y-%m-%d")
        retMsg.sessInfo.status = session.local_circuit_status
        if hasattr(sess, "icrqReq") and sess.icrqReq:
            icrq = L2tpv3ControlPacket.L2tpv3ControlPacket(
                remoteConnID=connection.remoteConnID, avps=session.avps_icrq)
            retMsg.sessInfo.icrqPktAvps = icrq.encode(
                reGenerateAvpStr=True)[12:]
        return retMsg
예제 #13
0
    def fsmStateRecipientIdle(self, event):
        """Callback function will called when fsm changed to this state.
        CDN is to be sent to remote and remove the session.

        :param event: The event that triggers the fsm to idle state.
        :return:

        """
        self.logger.debug(
            "Session [%d, %d] state is transferred to idle, event:" +
            event.src + " " + event.dst + "  " + event.event,
            self.localSessionId, self.remoteSessionId)
        self.lastchangetime = time.time()
        if event.event == "startup":
            # for startup, ignore it.
            return

        if event.event == L2tpv3Fsm.L2tpv3SessionRecipientFsm.EventRecvCDN and self.connection is not None:
            self.logger.debug(
                "We reach to this state since we receive a CDN, don't need to send the CDN again"
            )
            self.connection.transport.needSendZlb = True
            self.connection.removeSession(self)
            return

        # we should send the CDN to remote
        if event.event == L2tpv3Fsm.L2tpv3SessionRecipientFsm.EventCloseRequest:
            retcode = 3
            errorcode = 0
            msg = "Admin closes the session"

        else:  # fixme we should figure that
            retcode = 3
            errorcode = 0
            msg = "Admin closes the session"

        if self.connection is not None:
            self.logger.debug(
                "Send a CDN to remote since the session is terminated")
            if not self.silentlyCleared:
                transport = self.connection.transport
                cdn = L2tpv3ControlPacket.L2tpv3CDN(self, retcode, errorcode,
                                                    msg)
                transport.SendPacket(cdn, None)
            # Clean up the session
            self.connection.removeSession(self)
예제 #14
0
    def ReceiveCDN(self, pkt):
        """Receive a CDN packet, not check the AVP.

        :param pkt: The CDN control packet, has been decoded.
        :return: None

        """
        self.logger.debug("L2Tp session[%d, %d] receive a CDN message",
                          self.localSessionId, self.remoteSessionId)
        del self.avps_cdn[:]
        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                self.avps_cdn.append(avp)
        self.fsm.recvCDN()
        ackpkt = L2tpv3ControlPacket.L2tpv3ACK(
            connID=self.connection.remoteConnID)
        return ackpkt
예제 #15
0
 def sendSLI(self):
     if self.fsm.current == L2tpv3Fsm.L2tpv3SessionRecipientFsm.StateEstablished and\
             self.connection and self.connection.transport:
         msgAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
             L2tpv3RFC3931AVPs.ControlMessageAVP.SLI)
         localSessionId = L2tpv3RFC3931AVPs.LocalSessionID(
             self.localSessionId)
         remoteSessionId = L2tpv3RFC3931AVPs.RemoteSessionID(
             self.remoteSessionId)
         circuitstatus = L2tpv3RFC3931AVPs.CircuitStatus(
             active=self.local_circuit_status, new=False)
         sli = L2tpv3ControlPacket.L2tpv3ControlPacket(
             self.connection.remoteConnID,
             avps=(msgAvp, localSessionId, remoteSessionId, circuitstatus))
         self.connection.transport.SendPacket(sli)
         self.logger.info("send SLI status change to remote: " + "local:" +
                          str(self.localSessionId) + " remote:" +
                          str(self.remoteSessionId) + " status:" +
                          str(self.local_circuit_status))
예제 #16
0
    def recvSCCCN(self, pkt):
        """Receive a SCCCN pkt, we should process the avp and check the result.

        :param pkt:
        :return:

        """
        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.SCCCNMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                self.fsm.recvBadSCCCN()
                return
        self.transport.needSendZlb = True
        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                self.logger.debug(avp)
                # We got a bad SCCCN, we should send a CDN
                if not avp.handleAvp(pkt, None):
                    self.fsm.recvBadSCCCN()
                    return
        self.fsm.recvGoodSCCCN()

        if pkt.Connection.isRecoveryTunnel:
            recoverConn = pkt.Connection.recoverConnection

            if recoverConn is not None:
                recoverConn.resetTransport()
                recoverConn.isInRecovery = False
            # tear down the recovery tunnel
            pkt.Connection.StopConnection()

            if recoverConn is not None:
                # silently clear sessions not in an established state
                recoverConn.closeUnEstSessions()
                # Query the sessions that might have been in inconsistent states
                # based on data channel inactivity
                recoverConn.queryInactSessions()
        ackpkt = L2tpv3ControlPacket.L2tpv3ACK(connID=self.remoteConnID)
        return ackpkt
예제 #17
0
    def queryInactSessions(self):
        inActiveSessions = list()
        keys = self.sessions.keys()
        for sessionId in keys:
            session = self.sessions[sessionId]
            if session.local_circuit_status != L2tpv3Session.L2tpv3Session.CIRCUIT_STATUS_UP:
                self.logger.debug(
                    "query for inactive session [%d, %d]" %
                    (session.localSessionId, session.remoteSessionId))
                inActiveSessions.append(session)

        if inActiveSessions:
            fsqAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
                L2tpv3RFC3931AVPs.ControlMessageAVP.FSQ)
            fssAvps = tuple()
            for ses in inActiveSessions:
                fss = L2tpv3RFC3931AVPs.FailoverSessionState(
                    ses.localSessionId, ses.remoteSessionId)
                fssAvps = fssAvps + (fss, )
            fsq = L2tpv3ControlPacket.L2tpv3ControlPacket(
                self.remoteConnID, 0, 0, (fsqAvp, ) + fssAvps)
            self.transport.SendPacket(fsq)
예제 #18
0
    def queryStaleSessions(self):
        staleSessions = list()
        keys = self.sessions.keys()
        for sessionId in keys:
            session = self.sessions[sessionId]
            if session.stale:
                self.logger.debug(
                    "query for stale session [%d, %d]" %
                    (session.localSessionId, session.remoteSessionId))
                staleSessions.append(session)

        if staleSessions:
            fsqAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
                L2tpv3RFC3931AVPs.ControlMessageAVP.FSQ)
            fssAvps = tuple()
            for ses in staleSessions:
                fss = L2tpv3RFC3931AVPs.FailoverSessionState(
                    ses.localSessionId, ses.remoteSessionId)
                fssAvps = fssAvps + (fss, )
            fsq = L2tpv3ControlPacket.L2tpv3ControlPacket(
                self.remoteConnID, 0, 0, (fsqAvp, ) + fssAvps)
            self.transport.SendPacket(fsq)
예제 #19
0
    def ReceivePacket(self, pkt, addr):
        """The pkt is a control packet, with a connection ID Based on the
        RFc3931, we will use the ns value as the key, however, ns value only
        has 16bit, say, it will wrap when we reach 65535, so we have to
        consider this situation. A windowsize is considered to start from the
        self.ackNr, for wrap reason, we will add an wrap count variable, so the
        window start from:

            wrapCount * 65536 + self.ackNr
        AckNr|-------windowsize--------|

        a packet is considered to in the window:
            (pkt.ns >= ackNr) and (pkt.ns < ackNr + windowSize)
            (pkt.ns < ackNr) and (pkt.ns + 65536 > ackNr + windowSize)

        we also need to identify if the packet is early, or late.
        early, means the pkt is beyond the window, we will do nothing for the packet.
        late, we will consider we have processed this message, will send ack to it.

        """
        # The pkt should be decoded
        if not isinstance(pkt, L2tpv3ControlPacket.L2tpv3ControlPacket):
            self.logger.warn(L2tpv3TransportError.ParameterTypeError + ", the dispatcher is not instance of "
                             "L2tpv3ControlPacket.")
            raise L2tpv3TransportError(L2tpv3TransportError.ParameterTypeError)

        if self.connection.isInRecovery:
            self.logger.info(
                "Drop the control message since connection is in recovery")
            return

        if self.connection.isRecoveryTunnel:
            if not pkt.isZlb and pkt.avps[0].messageType not in L2tpv3RFC3931AVPs.ControlMessageAVP.RecoveryTunnelMesagedSet:
                self.logger.warn(
                    "Receive an invalid control message in recovery tunnel")
                return

        self.lastRecvTime = time.time()  # for process the connection timeout

        ns = pkt.ns
        nr = pkt.nr
        self.logger.debug("Receive a packet in transport layer:ns = %d, Nr = %d, "
                          "Current ns= %d and ackNr = %d " % (ns, nr, self.ns, self.ackNr))

        pkt.SetPacketTransport(self)
        pkt.SetPktConnection(self.connection)

        # remove the ack send
        while len(self.sendList) > 0 and self.sendList[0]["pkt"].ns < nr:
            self.sendList.pop(0)
        if pkt.isZlb:
            # For ZLB message, will not in the receive window
            return

        # insert the packet into the window, process the duplicate one and the
        # skip one
        tmpNs = ns
        if ns < self.ackNr:
            tmpNs += 65536

        # Check if the packet is a early packet, maybe we can use the 16bit
        # signed number for this:)
        tmpNr = self.ackNr
        if tmpNr < ns:
            tmpNr += 65536
        if (tmpNr - ns < 32768) and (tmpNr - ns > 0):  # late ones
            # will send the ZLB to remote
            self.logger.debug(
                "This packet is considered a duplicated one, send ack to it")
            self.SendPacket(L2tpv3ControlPacket.L2tpv3ZLB(
                self.connection.remoteConnID), addr)
            return

        if (tmpNs >= self.ackNr) and (tmpNs < self.ackNr + self.receiveWindowSize):
            if len(self.receiveWindow) >= self.receiveWindowSize:
                self.logger.warn(
                    "Receive window size reaches the max : %d", self.receiveWindowSize)
                pass  # Do we need send a ack?
            for item in self.receiveWindow.irange(pkt, pkt):
                self.logger.debug(
                    "pkt ns[%d] is already in receiveWindow", pkt.ns)
                break
            else:
                self.receiveWindow.add(pkt)
        else:
            self.logger.warn(
                "Receive a packet with wrong Nr/Ns, Nr:%d, Ns:%d, ackNr:%d, wrap_count:%d",
                nr, ns, self.ackNr, self.wrapCount)
            return

        # Give a chance to process the receive window
        # If we did not receive the window for a long time,
        self.logger.debug(
            "Receive a packet with windowsize:%d,firstNs=%d, ackNr=%d",
            len(self.receiveWindow), self.receiveWindow[0].ns, self.ackNr)
        while len(self.receiveWindow) > 0 and self.receiveWindow[0].ns == self.ackNr:
            self.ackNr += 1

            if self.ackNr >= 65536:
                self.wrapCount += 1
                self.ackNr = 0
            pktProcessing = self.receiveWindow.pop(0)
            retPkt = self.connection.HandlePkt(pktProcessing)
            if retPkt is not None:
                self.SendPacket(retPkt, addr=addr)
예제 #20
0
    def ReceiveICRQ(self, pkt):
        """Receive a ICRQ from remote, if it is a good ICRQ, will send a ICRP.

        :param pkt: The ICRQ control packet, has been decoded.
        :return: ICRP packet or None

        """

        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.connection.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.ICRQMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                self.fsm.recvBadICRQ()
                return L2tpv3ControlPacket.L2tpv3CDN(
                    self, 2, 4, "Avp cannot be handled correctly")

        self.logger.debug("L2tp session[%d, %d] receives a ICRQ message.",
                          self.localSessionId, self.remoteSessionId)

        avps = list()
        avps.append(
            L2tpv3RFC3931AVPs.ControlMessageAVP(
                L2tpv3RFC3931AVPs.ControlMessageAVP.ICRP))
        avps.append(
            L2tpv3RFC3931AVPs.DataSequencing(
                L2tpv3RFC3931AVPs.DataSequencing.AllSeq))
        # TODO  add sbfd support for ipv6
        if Convert.is_valid_ipv4_address(self.connection.localAddr):
            avps.append(
                L2tpv3RFC3931AVPs.SbfdDiscriminator(
                    int(
                        socket.inet_aton(
                            self.connection.localAddr).encode('hex'), 16)))
            avps.append(
                L2tpv3RFC3931AVPs.SbfdVccv(
                    L2tpv3RFC3931AVPs.SbfdVccv.VccvValue))

        # Need add some Cable labs avp
        self.logger.debug(
            "Session [%d, %d]sends a ICRP packet to remote, connection:%d",
            self.localSessionId, self.remoteSessionId,
            pkt.Connection.remoteConnID)

        icrp = L2tpv3ControlPacket.L2tpv3ControlPacket(
            pkt.Connection.remoteConnID, 0, 0, avps)
        del self.avps_icrq[:]
        del self.mcast[:]
        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                if isinstance(
                        avp,
                        L2tpv3CableLabsAvps.DepiL2SpecificSublayerSubtype):
                    self.session_l2Sublayer = avp.pw_type
                self.avps_icrq.append(avp)
                # We got a bad ICRQ, we should send a CDN
                if not avp.handleAvp(pkt, icrp):
                    self.fsm.recvBadICRQ()
                    return L2tpv3ControlPacket.L2tpv3CDN(
                        self, 2, 4, "Avp cannot be handled correctly")
        self.logger.debug("We got a good ICRQ, send to fsm")
        self.fsm.recvGoodICRQ()
        return icrp
예제 #21
0
    def ReceiveICRP(self, pkt):
        """Receive a ICRP from remote, if it is a good ICRP, will send a ICCN.
        this function will be used for simulator purpose.

        :param pkt: The ICRP control packet, has been decoded.
        :return:

        """
        if L2tpv3GlobalSettings.L2tpv3GlobalSettings.MustAvpsCheck is True:
            ret = self.connection.checkMustAvps(
                L2tpv3ControlPacket.L2tpv3ControlPacket.ICRPMandatoryAVPs,
                pkt.avps)
            if ret is not True:
                if isinstance(self.fsm, L2tpv3Fsm.L2tpv3SessionSenderFsm):
                    self.fsm.recvBadICRP()
                return L2tpv3ControlPacket.L2tpv3CDN(
                    self, 2, 4, "Avp cannot be handled correctly")

        self.logger.debug("Session [%d, %d] gets a l2tp ICRP message.",
                          self.localSessionId, self.remoteSessionId)

        if isinstance(self.fsm, L2tpv3Fsm.L2tpv3SessionRecipientFsm):
            self.logger.debug(
                "Recipient session [%d, %d] gets a l2tp ICRP message.",
                self.localSessionId, self.remoteSessionId)
            self.fsm.recvICRP()
            # this event will trigger the recipient state
            # machine transferring to idle state.
            return

        # Find the local session ID
        for avp in pkt.avps:
            if isinstance(avp, L2tpv3RFC3931AVPs.LocalSessionID):
                self.remoteSessionId = avp.sessionID
                self.connection.addSession(self)

        # If the incoming l2TP ICRP does not contain a local session ID
        if not self.remoteSessionId:
            self.logger.warn(
                "Session[%d, %d] is terminated due to not find the local session ID in ICRP message.",
                self.localSessionId, self.remoteSessionId)
            self.fsm.recvBadICRP()
            return L2tpv3ControlPacket.L2tpv3CDN(self, 2, 5, "")

        # send a ICCN
        msgAvp = L2tpv3RFC3931AVPs.ControlMessageAVP(
            L2tpv3RFC3931AVPs.ControlMessageAVP.ICCN)
        iccn = L2tpv3ControlPacket.L2tpv3ControlPacket(
            self.connection.remoteConnID, avps=(msgAvp, ))
        if len(pkt.avps) > 1:
            for i in xrange(1, len(pkt.avps)):
                avp = pkt.avps[i]
                # We got a bad ICRP, we should send a CDN
                if not avp.handleAvp(pkt, iccn):
                    self.fsm.recvBadICRP()
                    return L2tpv3ControlPacket.L2tpv3CDN(
                        self, 2, 4, "Avp cannot be handled correctly")

        self.logger.debug(
            "Sender session [%d, %d] gets a good l2tp ICRP message.",
            self.localSessionId, self.remoteSessionId)
        self.fsm.recvGoodICRP()
        return iccn
예제 #22
0
    def TimetickCallback(self):
        """Check the timers, we should process the lastSendtime and
        lastRecvTime."""
        currtime = time.time()

        # if some one changed the system time
        time_offset = 0
        if currtime - self.lastTimetick >= 5:
            self.logger.warn(
                "Transport[localAddr:%s, remoteAddr:%s, localConnectionID:%d, remoteConnection:%d] "
                "detected time change, current time is %f, lasttime tick time is %f" % (
                    self.localAddr, self.remoteAddr, self.connection.localConnID,
                    self.connection.remoteConnID, currtime,
                    self.lastTimetick
                ))
            # Try to update the resend list packet timeout
            if len(self.sendList) > 0:
                tLast = self.sendList[len(self.sendList) - 1]["time"]
                for resendStructure in self.sendList:
                    resendStructure["time"] = currtime + (
                        resendStructure["time"] - tLast)

            # Try to update the last recv time and last send time
            time_offset = currtime - self.lastTimetick

        elif currtime - self.lastTimetick < 0:
            self.logger.warn(
                "Transport[localAddr:%s, remoteAddr:%s, localConnectionID:%d, remoteConnection:%d] "
                "detected time change, current time is %f, lasttime tick time is %f" % (
                    self.localAddr, self.remoteAddr, self.connection.localConnID,
                    self.connection.remoteConnID, currtime, self.lastTimetick
                ))
            # Update sth, and trigger an event
            self.lastSendTime = self.lastTimetick - currtime - 1000
            if self.helloMsgTimeout > self.connectionTimeout:
                self.lastRecvTime = currtime - self.helloMsgTimeout - 1
            else:
                self.lastRecvTime = currtime - self.connectionTimeout - 1

            # Update the sendlist
            if len(self.sendList) > 0:
                tLast = self.sendList[len(self.sendList) - 1]["time"]
                for resendStructure in self.sendList:
                    resendStructure["time"] = currtime + (
                        resendStructure["time"] - tLast)

            # Try to update the last recv time and last send time
            time_offset = currtime - self.lastTimetick

        self.lastRecvTime += time_offset
        self.lastSendTime += time_offset
        self.lastTimetick = currtime
        if self.needSendZlb and self.lastSendTime + self.sendZlbTimeout < currtime:
            self.logger.debug("Send a ZLB message remote")
            self.SendPacket(
                L2tpv3ControlPacket.L2tpv3ZLB(self.connection.remoteConnID))
            self.needSendZlb = False

        # Process the lastSend
        if self.lastSendTime + self.helloMsgTimeout < currtime and self.lastRecvTime + self.helloMsgTimeout < currtime:
            self.logger.debug(
                "We don't receive any packet for long time, send a hello to remote.")
            if self.connection.fsm.current == self.connection.fsm.StateEstablished:
                self.SendPacket(
                    L2tpv3ControlPacket.L2tpv3Hello(self.connection.remoteConnID))

        if self.lastRecvTime + self.connectionTimeout < currtime:
            self.logger.debug(
                "The connection[%d] seems dead, close it!" % self.connection.localConnID, )
            self.notify.error(rpd_event_def.RPD_EVENT_L2TP_CONN_ERR[0],
                              rpd_event_def.RpdEventTag.ccap_ip(self.connection.remoteAddr))
            self.connection.CloseConnection()

        # Process the send list
        for resendStructure in self.sendList:
            if currtime > resendStructure["time"] + self.sendTimeout:
                self.logger.warn(
                    "Resend the packet %s to remote." % resendStructure)
                pkt = resendStructure["pkt"]
                self._reSendPacket(pkt)
                resendStructure["time"] = time.time()
                resendStructure["sendTimes"] += 1

                # if we resend the packets for a long time and not get the
                # response
                if resendStructure["sendTimes"] > self.resendTimes:
                    self.logger.warn("Connection[%d] has tried to send packet %d time(s), no response from remote, "
                                     "close the connection.", self.connection.localConnID,
                                     resendStructure["sendTimes"])
                    self.connection.CloseConnection()