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
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
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
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
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()
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
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
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)
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
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()
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
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
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)
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
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))
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
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)
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)
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)
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
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
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()