def get_config_update_capwap(self, seq): if 'config_update' in self._scapy_cache: self._scapy_cache['config_update'][20] = struct.pack('>B', seq) else: self._scapy_cache['config_update'] = c_buffer( bytes(CAPWAP_PKTS.config_update(self, seq))) return self._scapy_cache['config_update']
def get_echo_capwap(self): if 'echo_pkt' in self._scapy_cache: self._scapy_cache['echo_pkt'][20] = struct.pack( '!B', self.get_capwap_seq()) else: self._scapy_cache['echo_pkt'] = CAPWAP_PKTS.echo(self) return self._scapy_cache['echo_pkt']
def get_config_update_capwap(self, seq): if 'config_update' in self._scapy_cache: self._scapy_cache['config_update'][20] = struct.pack('!B', seq) else: self._scapy_cache['config_update'] = CAPWAP_PKTS.config_update( self, seq) return self._scapy_cache['config_update']
def control_round_trip(self, capw_ctrl_pkt, expected_response_type): """Send the packet, wait for the expected answer, and retry until max_retransmit. This is a generator for a APService, and returns True if success, and False otherwise. To be used in a APService as: success = yield self.from control_round_trip(capw_ctrl_pkt, expected_response_type=4) # expecting join response For 'expected_response_type', check scapy.contrib.capwap. Args: capw_ctrl_pkt (bytes): capwap control packet to send expected_response_type (int): type of the expected response (usually capw_ctrl_pkt's message type + 1) """ from ...trex_wireless_config import config RetransmitInterval = config.capwap.retransmit_interval for _ in range(config.capwap.max_retransmit): RetransmitInterval *= 2 encrypted = self.ap.encrypt(capw_ctrl_pkt) if encrypted and encrypted != '': tx_pkt_wrapped = self.ap.wrap_capwap_pkt( b'\1\0\0\0' + self.ap.encrypt(capw_ctrl_pkt)) self.ap.logger.debug("sending packet") self.send_pkt(tx_pkt_wrapped) else: continue # wait on expected response pkts = yield self.async_recv_pkt(time_sec=RetransmitInterval) if not pkts: continue pkt = pkts[0] # parsing # FIXME assumes specific length of lower layers (no vxlan, etc...) capwap_bytes = pkt[42:] capwap_hlen = (struct.unpack('!B', capwap_bytes[1:2])[ 0] & 0b11111000) >> 1 ctrl_header_type = struct.unpack( '!B', capwap_bytes[capwap_hlen + 3:capwap_hlen + 4])[0] result_code = CAPWAP_PKTS.parse_message_elements( capwap_bytes, capwap_hlen, self.ap, self) if result_code in (None, 0, 2) and ctrl_header_type == expected_response_type: # good return True elif result_code != -1: # non expected response self.ap.logger.warn('Service %s control round trip: Not successful result %s - %s for response type %d.' % (self.name, result_code, capwap_result_codes.get(result_code, 'Unknown'), ctrl_header_type)) return False else: continue # timeout self.ap.logger.info( "Service {} control round trip: rollback: timeout: too many trials".format(self.name)) return False
def get_echo_capwap(self): if 'echo_pkt' in self._scapy_cache: self._scapy_cache['echo_pkt'][20] = struct.pack( '>B', self.get_capwap_seq()) else: self._scapy_cache['echo_pkt'] = c_buffer( bytes(CAPWAP_PKTS.echo(self))) return self._scapy_cache['echo_pkt']
def get_echo_capwap(self): """"Return a Echo Request capwap control packet layer (payload of capwap).""" if 'echo_pkt' in self._scapy_cache: self._scapy_cache['echo_pkt'][20] = struct.pack( '!B', self.get_capwap_seq()) else: self._scapy_cache['echo_pkt'] = CAPWAP_PKTS.echo(self) return self._scapy_cache['echo_pkt']
def get_config_update_capwap(self, seq): """Return a configuration update response (capwap packet, payload of udp) with given sequence number. Args: seq: the sequence number of the capwap control header """ if 'config_update' in self._scapy_cache: self._scapy_cache['config_update'][20] = struct.pack('!B', seq) else: self._scapy_cache['config_update'] = CAPWAP_PKTS.config_update( self, seq) return self._scapy_cache['config_update']
def run_with_buffer(self): from ..trex_wireless_config import config def rollback(reason=None): if reason: self.ap.logger.info("Service ApJoinWLC rollback: %s" % reason) self.ap.state = APState.DISCOVER return ('service', ServiceAPDiscoverWLC(self.worker, self.ap, self.env, self.topics_to_subs)) try: while True: if self.ap.state != APState.JOIN: return self.ap.logger.info("Service ApJoinWLC started") self.ap.active_service = self self.ap.logger.debug('Sending Join Request') join_req = CAPWAP_PKTS.join(self.ap) ctrl_gen = self.control_round_trip(join_req, 4, debug_msg='Join Request') send_data = None while True: action = ctrl_gen.send(send_data) if action in ('good_resp', 'time', 'dtls_broke', 'err'): ctrl_gen.close() break else: send_data = yield action if action == 'dtls_broke': yield (rollback("dtls session broken")) return elif action == 'time': yield rollback("timeout: join request") return elif action == 'err': yield rollback("error") return self.ap.logger.debug('Got Join Response') self.ap.logger.debug('Sending Configuration Status Request') ctrl_gen = self.control_round_trip( CAPWAP_PKTS.conf_status_req(self.ap), 6, debug_msg='Config status request') send_data = None while True: action = ctrl_gen.send(send_data) if action in ('good_resp', 'time', 'dtls_broke', 'err'): ctrl_gen.close() break else: send_data = yield action if action == 'dtls_broke': yield (rollback("dtls session broken")) return elif action == 'time': yield rollback("timeout: join request") return elif action == 'err': yield rollback("error") return self.ap.logger.debug('Got Configuration Status Response') self.ap.logger.debug('Sending Change State Event Request') ctrl_gen = self.control_round_trip( CAPWAP_PKTS.change_state(self.ap, radio_id=0), 12, debug_msg='Change state event request') send_data = None while True: action = ctrl_gen.send(send_data) if action in ('good_resp', 'time', 'dtls_broke', 'err'): ctrl_gen.close() break else: send_data = yield action if action == "err": break if action == 'dtls_broke': yield (rollback("dtls session broken")) return elif action == 'time': yield rollback("timeout: join request") return elif action == 'err': yield rollback("error") return self.ap.logger.debug('Got Change State Event Response') self.ap.logger.debug('Sending Change State Event Request') ctrl_gen = self.control_round_trip( CAPWAP_PKTS.change_state(self.ap, radio_id=1), 12, debug_msg='Change state event request') send_data = None while True: action = ctrl_gen.send(send_data) if action in ('good_resp', 'time', 'dtls_broke', 'err'): ctrl_gen.close() break else: send_data = yield action if action == "err": break if action == 'dtls_broke': yield (rollback("dtls session broken")) return elif action == 'time': yield rollback("timeout: join request") return elif action == 'err': yield rollback("error") return self.ap.logger.debug('Got Change State Event Response') self.ap.logger.debug( 'Going to ack all config updates and try to get SSID') # ack all config updates in worker_traffic_handler thread # while not self.ap.last_recv_ts or self.ap.last_recv_ts + 5 >= time.time(): # self.waiting_on = simpy.events.Event(self.env) # yield ("process_with_timeout", self.waiting_on, 5) # del self.waiting_on # if not self.ap.is_dtls_established: # yield rollback("dtls not established") # return # elif self.ap.SSID: # break # if not self.ap.last_recv_ts: # break self.waiting_on = simpy.events.Event(self.env) yield ("process_with_timeout", self.waiting_on, config.capwap.specific.ssid_timeout) del self.waiting_on if not self.ap.SSID: yield rollback("no SSID") return self.ap.logger.info( "received SSID, proceding with sending data keep_alive") RetransmitInterval = config.capwap.retransmit_interval for _ in range(config.capwap.max_retransmit): if self.ap.state == APState.RUN: break if not self.ap.is_dtls_established: yield rollback("dtls not established") return RetransmitInterval *= 2 tx_pkt = self.ap.wrap_capwap_pkt(CAPWAP_PKTS.keep_alive( self.ap), dst_port=5247) self.ap.logger.debug("Sending keep-alive") yield ('put', tx_pkt) self.waiting_on = simpy.events.Event(self.env) yield ("process_with_timeout", self.waiting_on, RetransmitInterval) del self.waiting_on if self.ap.got_keep_alive: self.ap.got_keep_alive = False self.ap.logger.debug('Received Keep-alive response.') self.ap.last_echo_req_ts = time.time() self.ap.join_time = time.time() self.ap.join_duration = self.ap.join_time - self.ap.start_join_time self.ap.state = APState.RUN self.ap.logger.info("Service ApJoinWLC finished") # release spot yield ("done_ap") yield ('service', ServiceAPRun(self.worker, self.ap, self.env, self.topics_to_subs)) return if not self.ap.is_dtls_established: break # timeout if not self.ap.is_dtls_established: yield rollback("DTLS session broken") return # too many trials or failure if self.ap.state == APState.JOIN: yield rollback("too many trials") return except simpy.events.Interrupt: self.ap.logger.debug("Service APJoinWLC interrupted") return True
def run_with_buffer(self): from ..trex_wireless_config import config # request a slot yield ("start_ap") self.ap.logger.info("Service DiscoverWLC started") self.ap.start_join_time = time.time() while True: if self.ap.state > APState.DISCOVER: return yield ("service", ServiceAPShutdownDTLS(self.worker, self.ap, self.env, self.topics_to_subs)) self.ap.reset_vars() self.ap.state = APState.DISCOVER self.ap.active_service = self self.ap._create_ssl(config.openssl.buffer_size) self.ap.rx_responses[2] = -1 self.ap.retries += 1 # First resolve WLC MAC if needed if self.ap.wlc_ip_bytes and not self.ap.wlc_mac_bytes: self.ap.logger.info("Resolving WLC MAC for IP: %s" % self.ap.wlc_ip) while not self.ap.wlc_mac_bytes: RetransmitInterval = config.capwap.retransmit_interval for _ in range(config.capwap.max_retransmit): if self.ap.wlc_mac_bytes: break RetransmitInterval *= 2 self.ap.logger.debug("sending who-as for WLC IP") arp = self.ap.get_arp_pkt( 'who-has', src_mac_bytes=self.ap.mac_bytes, src_ip_bytes=self.ap.ip_bytes, dst_ip_bytes=self.ap.wlc_ip_bytes) yield ('put', arp) # waiting for an arp response self.waiting_on = simpy.events.Event(self.env) yield ("process_with_timeout", self.waiting_on, RetransmitInterval) del self.waiting_on if self.ap.wlc_mac_bytes: self.ap.logger.debug("got MAC of WLC") # done break if self.ap.wlc_ip_bytes and not self.ap.wlc_mac_bytes: self.err( 'err', 'Unable to resolve MAC address of WLC for %s' % self.ap.wlc_ip) RetransmitInterval = config.capwap.retransmit_interval for _ in range(config.capwap.max_retransmit): RetransmitInterval *= 2 discovery_pkt = self.ap.wrap_capwap_pkt(CAPWAP_PKTS.discovery( self.ap), is_discovery=True) self.ap.logger.debug("sending discovery request to WLC") yield ('put', discovery_pkt) self.waiting_on = simpy.events.Event(self.env) yield ("process_with_timeout", self.waiting_on, RetransmitInterval) del self.waiting_on try: result_code = self.ap.rx_responses[2] except KeyError: result_code = -1 yield ("err", 'No response') if result_code in (None, 0, 2): self.ap.state = APState.DTLS self.ap.logger.info("Service DiscoverWLC finished") yield ("service", ServiceAPEstablishDTLS(self.worker, self.ap, self.env, self.topics_to_subs)) elif result_code != -1: self.ap.wlc_mac_bytes = None self.ap.wlc_mac = None yield ("err", 'Not successful result %s - %s.' % (result_code, capwap_result_codes.get(result_code, 'Unknown'))) break self.ap.logger.info("DiscoverWLC retries expired")