def handle_ncqm_response(self, response, wtp, _): """Handle NCQM_RESPONSE message.""" block = wtp.blocks[response.iface_id] block.ncqm = {} for entry in response.entries: addr = EtherAddress(entry['addr']) block.ncqm[addr] = { 'addr': addr, 'last_rssi_std': entry['last_rssi_std'], 'last_rssi_avg': entry['last_rssi_avg'], 'last_packets': entry['last_packets'], 'hist_packets': entry['hist_packets'], 'mov_rssi': entry['mov_rssi'] } if wtp.addr not in self.ncqm: self.ncqm[wtp.addr] = {} self.ncqm[wtp.addr][block.block_id] = block.ncqm self.ucqm[wtp.addr][block.block_id]['timestamp'] = datetime.utcnow() # handle callbacks self.handle_callbacks()
def _handle_vap_status_response(self, status): """Handle an incoming STATUS_VAP message.""" bssid = EtherAddress(status.bssid) ssid = SSID(status.ssid) project = self.manager.projects_manager.load_project_by_ssid(ssid) if not project: self.log.warning("Unable to find SSID %s", ssid) self.send_del_vap(bssid) return # If the VAP does not exists, then create a new one if bssid not in self.manager.vaps: incoming = self.device.blocks[status.iface_id] self.manager.vaps[bssid] = VAP(bssid, incoming, project.wifi_props.ssid) vap = self.manager.vaps[bssid] self.log.info("VAP status: %s", vap)
def mcast_ip_to_ether(cls, ip_mcast_addr): """Transform an IP multicast address into an Ethernet one.""" if ip_mcast_addr is None: return '\x00' * 6 # The first 24 bits are fixed according to class D IP # and IP multicast address convenctions mcast_base = '01:00:5e' # The 23 low order bits are mapped. ip_addr_bytes = str(ip_mcast_addr).split('.') # The first IP byte is not use, # and only the last 7 bits of the second byte are used. second_byte = int(ip_addr_bytes[1]) & 127 third_byte = int(ip_addr_bytes[2]) fourth_byte = int(ip_addr_bytes[3]) mcast_upper = format(second_byte, '02x') + ':' + \ format(third_byte, '02x') + ':' + \ format(fourth_byte, '02x') return EtherAddress(mcast_base + ':' + mcast_upper)
def _handle_tx_policy_status_response(self, status): """Handle an incoming TX_POLICY_STATUS_RESPONSE message.""" block = self.device.blocks[status.iface_id] addr = EtherAddress(status.sta) if addr in self.manager.lvaps: lvap = self.manager.lvaps[addr] else: lvap = None if addr not in block.tx_policies: block.tx_policies[addr] = TxPolicy(addr, block, lvap) txp = block.tx_policies[addr] txp.set_mcs([float(x) / 2 for x in status.mcs]) txp.set_ht_mcs([int(x) for x in status.mcs_ht]) txp.set_rts_cts(status.rts_cts) txp.set_max_amsdu_len(status.max_amsdu_len) txp.set_mcast(status.tx_mcast) txp.set_no_ack(status.flags.no_ack) self.log.info("TX policy status %s", txp)
def get(self, *args, **kwargs): """List devices. Args: [0]: the device address (optional) Example URLs: GET /api/v1/wtps [ { "addr": "00:0D:B9:2F:56:64", "blocks": {}, "connection": null, "desc": "PC Engines ALIX 2D", "last_seen": 0, "last_seen_ts": "1970-01-01T01:00:00.000000Z", "period": 0, "state": "disconnected" } ] GET /api/v1/wtps/00:0D:B9:2F:56:64 (disconnected) { "addr": "00:0D:B9:2F:56:64", "blocks": {}, "connection": null, "desc": "PC Engines ALIX 2D", "last_seen": 0, "last_seen_ts": "1970-01-01T01:00:00.000000Z", "period": 0, "state": "disconnected" } GET /api/v1/wtps/00:0D:B9:2F:56:64 (connected) { "addr": "00:0D:B9:30:3E:18", "blocks": { "0": { "addr": "00:0D:B9:30:3E:18", "band": "HT20", "channel": 36, "ht_supports": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], "hwaddr": "04:F0:21:09:F9:9E", "supports": [ 6, 9, 12, 18, 24, 36, 48, 54 ], "tx_policies": { "60:F4:45:D0:3B:FC": { "addr": "60:F4:45:D0:3B:FC", "ht_mcs": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], "max_amsdu_len": 3839, "mcast": "legacy", "mcs": [ 6.0, 9.0, 12.0, 18.0, 24.0, 36.0, 48.0, 54.0 ], "no_ack": false, "rts_cts": 2436, "ur_count": 3 } } }, "1": { "addr": "00:0D:B9:30:3E:18", "band": "HT20", "channel": 6, "ht_supports": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], "hwaddr": "D4:CA:6D:14:C2:09", "supports": [ 1, 2, 5, 6, 9, 11, 12, 18, 24, 36, 48, 54 ], "tx_policies": {} } }, "connection": { "addr": [ "192.168.1.9", 46066 ] }, "desc": "PC Engines ALIX 2D", "last_seen": 8560, "last_seen_ts": "2019-08-23T13:09:43.140533Z", "period": 0, "state": "online" } """ return self.service.devices \ if not args else self.service.devices[EtherAddress(args[0])]
def get(self, *args, **kwargs): """List the LVAPs. Args: [0]: the lvap address (optional) Example URLs: GET /api/v1/lvaps [ { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": false, "authentication_state": false, "blocks": [ ... ], "bssid": null, "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": null, "state": "running", "wtp": { ... } } ] GET /api/v1/lvaps/60:F4:45:D0:3B:FC { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": false, "authentication_state": false, "blocks": [ ... ], "bssid": null, "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": null, "state": "running", "wtp": { ... } } """ return self.service.lvaps \ if not args else self.service.lvaps[EtherAddress(args[0])]
def get_prefix(self): """Return tenant prefix.""" tokens = [self.project_id.hex[0:12][i:i + 2] for i in range(0, 12, 2)] return EtherAddress(':'.join(tokens))
def decreaseQuantum(self, slc, wtp, ratesProm): res = False self.decreased_quantums = "" updated_slice = {} # para todos los lvaps en el wtp for sta in self.context.lvaps: lvap = self.context.lvaps[sta] if lvap.wtp != None and lvap.wtp.addr == wtp.to_str(): lvap_slice = self.getSliceLvap(sta) if not (self.change_quantum[lvap_slice][wtp]): promised_rate = ratesProm[lvap_slice] lvap_rate = self.getLVAPRateMBits(sta.to_str()) # si al menos un lvap tiene mayor rate al prometido y el quantum de esa slice en el wtp es mayor al minimo, le saco recursos if lvap_rate > promised_rate: actual_slice = self.context.wifi_slices[str( lvap_slice)] wtp_quantum = actual_slice.properties['quantum'] if EtherAddress(wtp) in actual_slice.devices: wtp_quantum = actual_slice.devices[wtp]['quantum'] if wtp_quantum > self.quantum_min: res = True self.change_quantum[lvap_slice][wtp] = True updated_slice = { 'slice_id': actual_slice.slice_id, 'properties': { 'amsdu_aggregation': actual_slice. properties['amsdu_aggregation'], 'quantum': actual_slice.properties['quantum'], 'sta_scheduler': actual_slice.properties['sta_scheduler'] }, 'devices': actual_slice.devices } addr = EtherAddress(wtp) if addr not in updated_slice['devices']: self.decreased_quantums = self.decreased_quantums + "// S-" + lvap_slice + "--" + str( updated_slice['properties']['quantum'] ) + "->" + str( updated_slice['properties']['quantum'] - updated_slice['properties']['quantum'] * self.quantum_decrease) updated_slice['devices'][addr] = { 'amsdu_aggregation': actual_slice. properties['amsdu_aggregation'], 'quantum': actual_slice.properties['quantum'] - actual_slice.properties['quantum'] * self.quantum_decrease, 'sta_scheduler': actual_slice.properties['sta_scheduler'] } else: self.decreased_quantums = self.decreased_quantums + "// S-" + lvap_slice + "--" + str( updated_slice['devices'][addr]['quantum'] ) + "->" + str( updated_slice['devices'][addr]['quantum'] - updated_slice['devices'][addr]['quantum'] * self.quantum_decrease) updated_slice['devices'][addr][ 'quantum'] = updated_slice['devices'][ addr]['quantum'] - updated_slice[ 'devices'][addr][ 'quantum'] * self.quantum_decrease self.context.upsert_wifi_slice(**updated_slice) #return updated_slice return res
def try_handover(self, sta, slc, rate, ratesProm, actual_rate): posibles_handovers = [] lvap = self.context.lvaps[EtherAddress(sta)] blocks = self.blocks().sort_by_rssi(lvap.addr) def filterBlocks(block): if block.ucqm[lvap.addr][ 'mov_rssi'] > self.RSSI_min and block.hwaddr.to_str( ) != lvap.blocks[0].hwaddr.to_str(): return True else: return False # Filtramos los wtp que tengan malo RSSI filtered_blocks = list(filter(filterBlocks, blocks)) # obtengo el uso del wtp actual query = 'select * from wifi_channel_stats where wtp=\'' + lvap.wtp.addr.to_str( ) + '\' and block_id=\'' + str( lvap.blocks[0].block_id) + '\' and time > now() - ' + str( int(self.every / 1000)) + 's;' result = self.query(query) current_channel_stats = list(result.get_points()) current_usage = 0 for current_stats in current_channel_stats: current_usage += current_stats[ 'tx'] # + current_stats['rx'] + current_stats['ed'] current_usage = current_usage / len(current_channel_stats) # obtengo historial de handovers para verificar ping pong query = 'select * from lvaps_handover where sta=\'' + sta + '\' and time > now() - ' + str( int(self.every / 1000) * 10) + 's;' result = self.query(query) handover_list = list(result.get_points()) for block in filtered_blocks: query = 'select * from wifi_channel_stats where wtp=\'' + block.wtp.addr.to_str( ) + '\' and block_id=\'' + str( block.block_id) + '\' and time > now() - ' + str( int(self.every / 1000)) + 's;' result = self.query(query) channel_stats = list(result.get_points()) usage = 0 for stats in channel_stats: usage += stats['tx'] #+ stats['rx'] + stats['ed'] usage = usage / len(channel_stats) # si el uso del wtp es menor al actual, lo agrego como posible handover if usage * 1.1 < current_usage and self.wtp_handovers[ block.wtp.addr] < self.max_handovers and not ( self.ping_pong(handover_list, block.wtp.addr)): posibles_handovers.append({'block': block, 'usage': usage}) if len(posibles_handovers) > 0: # Ordeno los bloques por usage asi me quedo con el que tenga menos posibles_handovers.sort(key=lambda x: x['usage']) # escribo en logger self.write_log( slc, sta, "H", lvap.blocks[0].wtp.addr.to_str() + "->" + posibles_handovers[0]['block'].wtp.addr.to_str(), "Usage new WTP: " + str(posibles_handovers[0]['usage'])) # Do Handover lvap.blocks = posibles_handovers[0]['block'] self.wtp_handovers[posibles_handovers[0]['block'].wtp.addr] += 1 # guardar cambios # generate data points points = [] timestamp = datetime.utcnow() fields = {"wtp": posibles_handovers[0]['block'].wtp.addr} tags = {"sta": sta} sample = { "measurement": 'lvaps_handover', "tags": tags, "time": timestamp, "fields": fields } points.append(sample) # save to db self.write_points(points) return True else: # No encontre WTP con uso menor al actual, entonces me fijo si algun wtp tiene lvaps con rate mayor al prometido for block in filtered_blocks: extra_rate = 0 for sta2 in self.context.lvaps: lvap = self.context.lvaps[sta2] if lvap.wtp != None and lvap.wtp.addr == block.wtp.addr: lvap_slice = self.getSliceLvap(sta2) promised_rate = ratesProm[lvap_slice] lvap_rate = self.getLVAPRateMBits(sta2.to_str()) if (lvap_rate - promised_rate) > 0: extra_rate += (lvap_rate - promised_rate) if extra_rate > 0 and ( extra_rate >= (actual_rate * 1.2) or extra_rate >= rate) and self.wtp_handovers[ block.wtp.addr] < self.max_handovers and not ( self.ping_pong(handover_list, block.wtp.addr)): posibles_handovers.append({ 'block': block, 'extra_rate': extra_rate }) if len(posibles_handovers) > 0: # Ordeno los bloques por rate extra asi me quedo con el que tenga mas posibles_handovers.sort(key=lambda x: x['extra_rate']) # escribo en logger self.write_log( slc, sta, "H", lvap.blocks[0].wtp.addr.to_str() + "->" + posibles_handovers[0]['block'].wtp.addr.to_str(), "Extra rate new WTP: " + str(posibles_handovers[0]['extra_rate'])) # Do Handover lvap.blocks = posibles_handovers[-1]['block'] self.wtp_handovers[posibles_handovers[-1] ['block'].wtp.addr] += 1 # guardar cambios # generate data points points = [] timestamp = datetime.utcnow() fields = {"wtp": posibles_handovers[-1]['block'].wtp.addr} tags = {"sta": sta} sample = { "measurement": 'lvaps_handover', "tags": tags, "time": timestamp, "fields": fields } points.append(sample) # save to db self.write_points(points) return True else: return False
def _handle_lvap_status_response(self, status): """Handle an incoming LVAP_STATUS_RESPONSE message.""" sta = EtherAddress(status.sta) # If the LVAP does not exists, then create a new one if sta not in self.manager.lvaps: self.manager.lvaps[sta] = \ LVAP(sta, assoc_id=status.assoc_id, state=PROCESS_RUNNING) lvap = self.manager.lvaps[sta] # update LVAP params lvap.encap = EtherAddress(status.encap) lvap.authentication_state = bool(status.flags.authenticated) lvap.association_state = bool(status.flags.associated) lvap.ht_caps = bool(status.flags.ht_caps) lvap.ht_caps_info = dict(status.ht_caps_info) del lvap.ht_caps_info['_io'] ssid = SSID(status.ssid) if ssid == SSID(): ssid = None bssid = EtherAddress(status.bssid) if bssid == EtherAddress("00:00:00:00:00:00"): bssid = None lvap.bssid = bssid incoming = self.device.blocks[status.iface_id] if status.flags.set_mask: lvap.downlink = incoming else: lvap.uplink.append(incoming) # if this is not a DL+UL block then stop here if not status.flags.set_mask: return # if an SSID is set and the incoming SSID is different from the # current one then raise an LVAP leave event if lvap.ssid and ssid != lvap.ssid: self.send_client_leave_message_to_self(lvap) lvap.ssid = None # if the incoming ssid is not none then raise an lvap join event if ssid: lvap.ssid = ssid self.send_client_join_message_to_self(lvap) # udpate networks networks = list() for network in status.networks: incoming = (EtherAddress(network.bssid), SSID(network.ssid)) networks.append(incoming) lvap.networks = networks self.log.info("LVAP status: %s", lvap)
def _handle_auth_request(self, request): """Handle an incoming AUTH_REQUEST message.""" sta = EtherAddress(request.sta) if sta not in self.manager.lvaps: self.log.info("Auth request from unknown LVAP %s", sta) return lvap = self.manager.lvaps[sta] incoming_bssid = EtherAddress(request.bssid) # The request bssid is the lvap current bssid, then just reply if lvap.bssid == incoming_bssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return # Otherwise check if the requested BSSID belongs to a unique tenant for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED: continue bssid = project.generate_bssid(lvap.addr) if bssid == incoming_bssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return # Finally check if this is a shared bssid for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE: continue if incoming_bssid in project.vaps: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return self.log.info("Auth request from unknown BSSID %s", incoming_bssid)
def _handle_probe_request(self, request): """Handle an incoming PROBE_REQUEST message.""" # Get station sta = EtherAddress(request.sta) # Incoming incoming_ssid = SSID(request.ssid) iface_id = request.iface_id ht_caps = request.flags.ht_caps ht_caps_info = dict(request.ht_caps_info) del ht_caps_info['_io'] msg = "Probe request from %s ssid %s iface_id %u ht_caps %u" if not incoming_ssid: self.log.debug(msg, sta, "Broadcast", iface_id, ht_caps) else: self.log.debug(msg, sta, incoming_ssid, iface_id, ht_caps) # Check is station is in ACL of any networks networks = self.manager.projects_manager.get_available_ssids(sta) if not networks: self.log.debug("No SSID available at this device") return # If lvap does not exist then create it. Otherwise just refresh the # list of available networks if sta not in self.manager.lvaps: # spawn new LVAP self.log.info("Spawning new LVAP %s on %s", sta, self.device.addr) assoc_id = randint(1, 2007) lvap = LVAP(sta, assoc_id=assoc_id) lvap.networks = networks lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info # this will trigger an LVAP ADD message lvap.blocks = self.device.blocks[request.iface_id] # save LVAP in the runtime self.manager.lvaps[sta] = lvap # Send probe response self.send_probe_response(lvap, incoming_ssid) return lvap = self.manager.lvaps[sta] # If this probe request is not coming from the same interface on which # this LVAP is currenly running then ignore the probe if lvap.blocks[0].block_id != iface_id: return # If LVAP is not running then ignore if not lvap.is_running(): return # Update list of available networks lvap.networks = networks lvap.commit() # Send probe response self.send_probe_response(lvap, incoming_ssid)
def on_read(self, future): """Assemble message from agent. Appends bytes read from socket to a buffer. Once the full packet has been read the parser is invoked and the buffers is cleared. The parsed packet is then passed to the suitable method or dropped if the packet type in unknown. """ try: self.buffer = self.buffer + future.result() except StreamClosedError as stream_ex: self.log.error(stream_ex) return hdr = self.proto.HEADER.parse(self.buffer) if len(self.buffer) < hdr.length: remaining = hdr.length - len(self.buffer) future = self.stream.read_bytes(remaining) future.add_done_callback(self.on_read) return # Check if we know the message type if hdr.tsrc.action not in self.proto.PT_TYPES: self.log.warning("Unknown message type %u, ignoring.", hdr.tsrc.action) return # Check if the Device is among the ones we known addr = EtherAddress(hdr.device) if addr not in self.manager.devices: self.log.warning("Unknown Device %s, closing connection.", addr) self.stream.close() return device = self.manager.devices[addr] # Log message informations parser = self.proto.PT_TYPES[hdr.tsrc.action][0] name = self.proto.PT_TYPES[hdr.tsrc.action][1] msg = parser.parse(self.buffer) self.log.debug("Got %s message from %s seq %u", name, EtherAddress(addr), msg.seq) # If Device is not online and is not connected, then the only message # type we can accept is HELLO_RESPONSE if not device.is_connected(): if msg.tsrc.action != self.proto.PT_HELLO_SERVICE: if not self.stream.closed(): self.wait() return # This is a new connection, set pointer to the device self.device = device # The set pointer from device connection to this object device.connection = self # Transition to connected state device.set_connected() # Start hb worker self.hb_worker.start() # Send caps request self.send_caps_request() # If device is not online but it is connected, then we can accept both # HELLO_RESPONSE and CAP_RESPONSE message if device.is_connected() and not device.is_online(): valid = (self.proto.PT_HELLO_SERVICE, self.proto.PT_CAPABILITIES_SERVICE) if msg.tsrc.action not in valid: if not self.stream.closed(): self.wait() return # Otherwise handle message try: self.handle_message(name, msg) except Exception as ex: self.log.exception(ex) self.stream.close() if not self.stream.closed(): self.wait()
def addr(self, addr): """ Set the station address. """ self.params['addr'] = EtherAddress(addr)
def get(self, *args, **kwargs): """List the LVAPs. Args: [0], the project id (mandatory) [1]: the lvap address (optional) Example URLs: GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/lvaps [ { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": true, "authentication_state": true, "blocks": [ ... ], "bssid": "52:31:3E:D0:3B:FC", "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": "EmPOWER", "state": "running", "wtp": { ... } } ] GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/lvaps/ 60:F4:45:D0:3B:FC { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": true, "authentication_state": true, "blocks": [ ... ], "bssid": "52:31:3E:D0:3B:FC", "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": "EmPOWER", "state": "running", "wtp": { ... } } """ project_id = uuid.UUID(args[0]) project = self.service.projects[project_id] return project.lvaps \ if len(args) == 1 else project.lvaps[EtherAddress(args[1])]
def _handle_assoc_request(self, request): """Handle an incoming ASSOC_REQUEST message.""" sta = EtherAddress(request.sta) ht_caps = request.flags.ht_caps ht_caps_info = dict(request.ht_caps_info) del ht_caps_info['_io'] if sta not in self.manager.lvaps: self.log.info("Assoc request from unknown LVAP %s", sta) return lvap = self.manager.lvaps[sta] incoming_bssid = EtherAddress(request.bssid) if lvap.bssid != incoming_bssid: self.log.info("Assoc request for invalid BSSID %s", incoming_bssid) return incoming_ssid = SSID(request.ssid) # Check if the requested SSID is from a unique project for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED: continue bssid = project.generate_bssid(lvap.addr) if bssid != incoming_bssid: self.log.info("Invalid BSSID %s", incoming_bssid) continue if project.wifi_props.ssid == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info lvap.commit() self.send_assoc_response(lvap) return # Check if the requested SSID is from a unique project for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE: continue if incoming_bssid not in project.vaps: self.log.info("Invalid BSSID %s", incoming_bssid) continue if project.wifi_props.ssid == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info lvap.commit() self.send_assoc_response(lvap) return self.log.info("Unable to find SSID %s", incoming_ssid)
def sta(self, sta): """ Set the station address. """ self.params['sta'] = EtherAddress(sta)
def handle_lvap_response(self, response, *_): """Handle BIN_COUNTERS_RESPONSE message.""" # get lvap mac address sta = EtherAddress(response.sta) sta = sta.to_str() # update this object tx_samples = response.stats[0:response.nb_tx] rx_samples = response.stats[response.nb_tx:-1] old_tx_bytes = self.lvap_counters[sta][ "tx_bytes"] if sta in self.lvap_counters else 0.0 old_rx_bytes = self.lvap_counters[sta][ "rx_bytes"] if sta in self.lvap_counters else 0.0 old_tx_packets = self.lvap_counters[sta][ "tx_packets"] if sta in self.lvap_counters else 0.0 old_rx_packets = self.lvap_counters[sta][ "rx_packets"] if sta in self.lvap_counters else 0.0 if not (sta in self.lvap_counters): self.lvap_counters[sta] = {} self.lvap_counters[sta]["tx_bytes"] = self.fill_bytes_samples( tx_samples) self.lvap_counters[sta]["rx_bytes"] = self.fill_bytes_samples( rx_samples) self.lvap_counters[sta]["tx_packets"] = self.fill_packets_samples( tx_samples) self.lvap_counters[sta]["rx_packets"] = self.fill_packets_samples( rx_samples) self.lvap_counters[sta]["tx_bps"] = 0 self.lvap_counters[sta]["rx_bps"] = 0 self.lvap_counters[sta]["tx_pps"] = 0 self.lvap_counters[sta]["rx_pps"] = 0 if sta in self.lvap_last and self.lvap_last[sta] != None: delta = time.time() - self.lvap_last[sta] self.lvap_counters[sta]["tx_bps"] = \ self.update_stats(delta, old_tx_bytes, self.lvap_counters[sta]["tx_bytes"]) self.lvap_counters[sta]["rx_bps"] = \ self.update_stats(delta, old_rx_bytes, self.lvap_counters[sta]["rx_bytes"]) self.lvap_counters[sta]["tx_pps"] = \ self.update_stats(delta, old_tx_packets, self.lvap_counters[sta]["tx_packets"]) self.lvap_counters[sta]["rx_pps"] = \ self.update_stats(delta, old_rx_packets, self.lvap_counters[sta]["rx_packets"]) # generate data points points = [] timestamp = datetime.utcnow() fields = { "tx_bytes": float(self.lvap_counters[sta]["tx_bytes"]), "rx_bytes": float(self.lvap_counters[sta]["rx_bytes"]), "tx_packets": float(self.lvap_counters[sta]["tx_packets"]), "rx_packets": float(self.lvap_counters[sta]["rx_packets"]), "tx_bps": float(self.lvap_counters[sta]["tx_bps"]), "rx_bps": float(self.lvap_counters[sta]["rx_bps"]), "tx_pps": float(self.lvap_counters[sta]["tx_pps"]), "rx_pps": float(self.lvap_counters[sta]["rx_pps"]) } tags = dict(self.params) tags["sta"] = sta sample = { "measurement": 'lvap_counters_stats', "tags": tags, "time": timestamp, "fields": fields } points.append(sample) # save to db self.write_points(points) # handle callbacks self.handle_callbacks() # set last iteration time self.lvap_last[sta] = time.time() # handle rc stats response self.handle_class_rc_response(sta)