def handle_poller_response(self, message): """Handle an incoming poller response message. Args: message, a poller response message Returns: None """ if message.poller_id not in self.modules: return wtp_addr = EtherAddress(message.wtp) if wtp_addr not in RUNTIME.wtps: return wtp = RUNTIME.wtps[wtp_addr] hwaddr = EtherAddress(message.hwaddr) incoming = ResourcePool() incoming.add(ResourceBlock(wtp, hwaddr, message.channel, message.band)) matching = (wtp.supports & incoming).pop() LOG.info("Received %s response from %s (id=%u)", self.MODULE_NAME, matching, message.poller_id) # find poller object poller = self.modules[message.poller_id] # handle the message map_type = self.MODULE_NAME setattr(poller.block, map_type, CQM()) map_entry = getattr(poller.block, map_type) for entry in message.img_entries: addr = EtherAddress(entry[0]) if not addr.match(poller.addrs): continue value = {'addr': addr, 'last_rssi_std': entry[1] / 1000.0, 'last_rssi_avg': entry[2] / 1000.0, 'last_packets': entry[3], 'hist_packets': entry[4], 'ewma_rssi': entry[5] / 1000.0, 'sma_rssi': entry[6] / 1000.0} map_entry[addr] = value # call callback handle_callback(poller, poller)
def send_add_lvap(self, lvap, block, set_mask): """Send a ADD_LVAP message. Args: lvap: an LVAP object Returns: None Raises: TypeError: if lvap is not an LVAP object. """ flags = Container(authenticated=lvap.authentication_state, associated=lvap.association_state, set_mask=set_mask) encap = EtherAddress("00:00:00:00:00:00") if lvap.encap: encap = lvap.encap add_lvap = Container(version=PT_VERSION, type=PT_ADD_LVAP, length=44, seq=self.wtp.seq, flags=flags, assoc_id=lvap.assoc_id, hwaddr=block.hwaddr.to_raw(), channel=block.channel, band=block.band, sta=lvap.addr.to_raw(), encap=encap.to_raw(), net_bssid=lvap.net_bssid.to_raw(), lvap_bssid=lvap.lvap_bssid.to_raw(), ssids=[]) if lvap.ssid: b_ssid = lvap.ssid.to_raw() tmp = Container(length=len(b_ssid), ssid=b_ssid) add_lvap.ssids.append(tmp) add_lvap.length = add_lvap.length + len(b_ssid) + 1 else: add_lvap.ssids.append(Container(length=0, ssid=b'')) add_lvap.length = add_lvap.length + 1 for ssid in lvap.ssids: b_ssid = ssid.to_raw() tmp = Container(length=len(b_ssid), ssid=b_ssid) add_lvap.ssids.append(tmp) add_lvap.length = add_lvap.length + len(b_ssid) + 1 LOG.info("Add lvap %s", lvap) msg = ADD_LVAP.build(add_lvap) self.stream.write(msg)
def __start_adv(self): """Star ctrl advertising.""" sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) info = fcntl.ioctl(sock.fileno(), 0x8927, struct.pack('256s', self.__ifname[:15].encode('utf-8'))) src = EtherAddress(':'.join(['%02x' % char for char in info[18:24]])) dst = EtherAddress("FF:FF:FF:FF:FF:FF") adv = Container(dst=dst.to_raw(), src=src.to_raw(), eth_type=0xEEEE, ctrl=self.__ctrl_ip.packed, port=self.__ctrl_port) self.__msg = CTRL_ADV.build(adv) self.__auto_cfg = \ tornado.ioloop.PeriodicCallback(self.__auto_cfg_loop, 2000) self.__auto_cfg.start()
def generate_bssid(base_mac, sta_mac): """ Generate a new BSSID address. """ base = str(base_mac).split(":")[0:3] sta = str(sta_mac).split(":")[3:6] return EtherAddress(":".join(base + sta))
def wtp(self, value): """Set the WTP Address.""" self._wtp = EtherAddress(value)
def get_prefix(self): """Return tenant prefix.""" tokens = [self.tenant_id.hex[0:12][i:i + 2] for i in range(0, 12, 2)] return EtherAddress(':'.join(tokens))
def _handle_probe_request(self, wtp, request): """Handle an incoming PROBE_REQUEST message. Args: request, a PROBE_REQUEST message Returns: None """ # Check if block is valid valid = wtp.get_block(request.hwaddr, request.channel, request.band) if not valid: self.log.warning("No valid intersection found. Ignoring request.") return # check is station is in ACL sta = EtherAddress(request.sta) if not RUNTIME.is_allowed(sta): return # Requested BSSID incoming_ssid = SSID(request.ssid) if incoming_ssid == b'': self.log.info("Probe request from %s ssid %s", sta, "Broadcast") else: self.log.info("Probe request from %s ssid %s", sta, incoming_ssid) # generate list of available networks networks = list() for tenant in RUNTIME.tenants.values(): if tenant.bssid_type == T_TYPE_SHARED: continue for wtp_in_tenant in tenant.wtps.values(): if wtp.addr == wtp_in_tenant.addr: bssid = tenant.generate_bssid(sta) ssid = tenant.tenant_name networks.append((bssid, ssid)) if not networks: self.log.info("No Networks available at this WTP") return # If lvap does not exist then create it. Otherwise just refresh list # of networks if sta not in RUNTIME.lvaps: # spawn new LVAP self.log.info("Spawning new LVAP %s on %s", sta, wtp.addr) assoc_id = RUNTIME.assoc_id() lvap = LVAP(sta, assoc_id=assoc_id) lvap.networks = networks lvap.supported_band = request.supported_band # this will trigger an LVAP ADD message lvap.blocks = valid[0] # save LVAP in the runtime RUNTIME.lvaps[sta] = lvap # Send probe response self.send_probe_response(lvap, incoming_ssid) return # Update networks lvap = RUNTIME.lvaps[sta] lvap.networks = networks lvap.commit() # Send probe response if lvap.wtp == wtp: self.send_probe_response(lvap, incoming_ssid)
def _handle_assoc_request(self, wtp, request): """Handle an incoming ASSOC_REQUEST message. Args: request, a ASSOC_REQUEST message Returns: None """ sta = EtherAddress(request.sta) if sta not in RUNTIME.lvaps: self.log.info("Assoc request from unknown LVAP %s", sta) return lvap = RUNTIME.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 tenant for tenant in RUNTIME.tenants.values(): if tenant.bssid_type == T_TYPE_SHARED: continue bssid = tenant.generate_bssid(lvap.addr) if bssid != incoming_bssid: self.log.info("Invalid BSSID %s", incoming_bssid) continue if tenant.tenant_name == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.supported_band = request.supported_band lvap.commit() self.send_assoc_response(lvap) return # Check if the requested SSID is from a unique tenant for tenant in RUNTIME.tenants.values(): if tenant.bssid_type == T_TYPE_UNIQUE: continue if incoming_bssid not in tenant.vaps: self.log.info("Invalid BSSID %s", incoming_bssid) continue ssid = tenant.vaps[incoming_bssid].ssid if ssid == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.supported_band = request.supported_band lvap.commit() self.send_assoc_response(lvap) return self.log.info("Unable to find SSID %s", incoming_ssid)
def _handle_status_lvap(self, status): """Handle an incoming STATUS_LVAP message. Args: status, a STATUS_LVAP message Returns: None """ wtp_addr = EtherAddress(status.wtp) try: wtp = RUNTIME.wtps[wtp_addr] except KeyError: LOG.info("Status from unknown WTP %s", wtp_addr) return if not wtp.connection: LOG.info("Status from disconnected WTP %s", wtp_addr) return sta_addr = EtherAddress(status.sta) set_mask = bool(status.flags.set_mask) lvap = None hwaddr = EtherAddress(status.hwaddr) block = ResourceBlock(wtp, hwaddr, status.channel, status.band) LOG.info("LVAP status update from %s", sta_addr) # If the LVAP does not exists, then create a new one if sta_addr not in RUNTIME.lvaps: net_bssid_addr = EtherAddress(status.net_bssid) lvap_bssid_addr = EtherAddress(status.lvap_bssid) lvap = LVAP(sta_addr, net_bssid_addr, lvap_bssid_addr) # TODO: This should be built starting from the status message lvap.supports.add(ResourceBlock(lvap, sta_addr, 1, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 2, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 3, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 4, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 5, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 6, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 7, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 8, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 9, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 10, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 11, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 36, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta_addr, 48, BT_L20)) RUNTIME.lvaps[sta_addr] = lvap lvap = RUNTIME.lvaps[sta_addr] # incoming block pool = ResourcePool() pool.add(block) match = wtp.supports & pool if not match: LOG.error("Incoming block %s is invalid", block) return block = match.pop() # this will try to updated the lvap object with the resource block # coming in this status update message. try: if set_mask: # set downlink+uplink block lvap._downlink.setitem(block, RadioPort(lvap, block)) else: # set uplink only blocks lvap._uplink.setitem(block, RadioPort(lvap, block)) except ValueError: LOG.error("Error while importing block %s, removing.", block) block.radio.connection.send_del_lvap(lvap) return lvap.authentication_state = bool(status.flags.authenticated) lvap.association_state = bool(status.flags.associated) lvap._assoc_id = status.assoc_id lvap._encap = EtherAddress(status.encap) ssids = [SSID(x.ssid) for x in status.ssids] if lvap.ssid: # Raise LVAP leave event LOG.info("LVAP LEAVE %s (%s)", lvap.addr, lvap.ssid) for handler in self.server.pt_types_handlers[PT_LVAP_LEAVE]: handler(lvap) # removing LVAP from tenant, need first to look for right tenant if lvap.addr in lvap.tenant.lvaps: LOG.info("Removing %s from tenant %s", lvap.addr, lvap.ssid) del lvap.tenant.lvaps[lvap.addr] lvap._tenant = None if ssids[0]: # setting tenant without seding out add lvap message lvap._tenant = RUNTIME.load_tenant(ssids[0]) # adding LVAP to tenant LOG.info("Adding %s to tenant %s", lvap.addr, ssids[0]) lvap.tenant.lvaps[lvap.addr] = lvap # Raise LVAP join event LOG.info("LVAP JOIN %s (%s)", lvap.addr, lvap.ssid) for handler in self.server.pt_types_handlers[PT_LVAP_JOIN]: handler(lvap) # update remaining ssids lvap._ssids = ssids[1:] # set ports lvap.set_ports() LOG.info("LVAP status %s", lvap)
def lvap(self, value): """Set the LVAP Address.""" self._lvap = EtherAddress(value)
def _handle_status_lvap(self, wtp, status): """Handle an incoming STATUS_LVAP message. Args: status, a STATUS_LVAP message Returns: None """ if not wtp.connection: LOG.info("Status from disconnected WTP %s", wtp.addr) return sta = EtherAddress(status.sta) set_mask = bool(status.flags.set_mask) lvap = None accum = [] incoming_ssids = [SSID(x.ssid) for x in status.ssids] accum.append("addr ") accum.append(EtherAddress(status.sta).to_str()) accum.append(" net_bssid ") accum.append(EtherAddress(status.net_bssid).to_str()) accum.append(" lvap_bssid ") accum.append(EtherAddress(status.lvap_bssid).to_str()) accum.append(" ssid ") if incoming_ssids[0]: accum.append(incoming_ssids[0].to_str()) else: accum.append("None") accum.append(" ssids [") for ssid in incoming_ssids[1:]: accum.append(" ") accum.append(ssid.to_str()) accum.append(" ]") accum.append(" assoc_id ") accum.append(str(status.assoc_id)) if bool(status.flags.authenticated): accum.append(" AUTH") if bool(status.flags.associated): accum.append(" ASSOC") LOG.info("LVAP status %s", ''.join(accum)) # If the LVAP does not exists, then create a new one if sta not in RUNTIME.lvaps: net_bssid_addr = EtherAddress(status.net_bssid) lvap_bssid_addr = EtherAddress(status.lvap_bssid) lvap = LVAP(sta, net_bssid_addr, lvap_bssid_addr) RUNTIME.lvaps[sta] = lvap lvap = RUNTIME.lvaps[sta] # Check if block is valid incoming = ResourceBlock(wtp, EtherAddress(status.hwaddr), status.channel, status.band) valid = [block for block in wtp.supports if block == incoming] if not valid: LOG.warning("No valid intersection found. Removing block.") wtp.connection.send_del_lvap(lvap) return # this will try to updated the lvap object with the resource block # coming in this status update message. try: if set_mask: # set downlink+uplink block lvap._downlink.setitem(valid[0], RadioPort(lvap, valid[0])) else: # set uplink only blocks lvap._uplink.setitem(valid[0], RadioPort(lvap, valid[0])) except Exception as e: LOG.exception(e) LOG.error("Error while importing block %s, removing.", valid[0]) wtp.connection.send_del_lvap(lvap) return # update LVAP ports lvap.ports[0] = VirtualPortLvap(phy_port=wtp.port(), virtual_port_id=0, lvap=lvap) # set supported band lvap.supported_band = status.supported_band # update LVAP params lvap.authentication_state = bool(status.flags.authenticated) lvap.association_state = bool(status.flags.associated) lvap._assoc_id = status.assoc_id lvap._encap = EtherAddress(status.encap) ssids = [SSID(x.ssid) for x in status.ssids] # update ssid if lvap.ssid: # Raise LVAP leave event self.server.send_lvap_leave_message_to_self(lvap) # removing LVAP from tenant, need first to look for right tenant if lvap.addr in lvap.tenant.lvaps: LOG.info("Removing %s from tenant %s", lvap.addr, lvap.ssid) del lvap.tenant.lvaps[lvap.addr] lvap._tenant = None # update remaining ssids lvap._ssids = ssids[1:] if ssids[0]: tenant = RUNTIME.load_tenant(ssids[0]) if not tenant: LOG.info("LVAP %s from unknown tenant %s", lvap.addr, ssids[0]) RUNTIME.remove_lvap(lvap.addr) return # setting tenant without seding out add lvap message lvap._tenant = tenant # adding LVAP to tenant LOG.info("Adding %s to tenant %s", lvap.addr, ssids[0]) lvap.tenant.lvaps[lvap.addr] = lvap # Raise LVAP join event self.server.send_lvap_join_message_to_self(lvap)
def wtp_addrs(self, value): """Set wtp_addrs.""" self.__wtp_addrs = [EtherAddress(x) for x in value.split(",")]
from empower.core.lvap import LVAP from empower.core.networkport import NetworkPort from empower.core.vap import VAP from empower.lvapp import PT_ADD_VAP from empower.lvapp import ADD_VAP from empower.core.tenant import T_TYPE_SHARED from empower.core.tenant import T_TYPE_UNIQUE from empower.core.utils import generate_bssid from empower.core.virtualport import VirtualPortLvap from empower.main import RUNTIME import empower.logger LOG = empower.logger.get_logger() BASE_MAC = EtherAddress("02:ca:fe:00:00:00") class LVAPPConnection(object): """LVAPP Connection. Represents a connection to a WTP (Wireless Termination Point) using the LVAP Protocol. One LVAPPConnection object is created for every WTP in the network. The object implements the logic for handling incoming messages. The currently supported messages are: Hello. WTP to AC. Used as keepalive between the WTP and the AC Probe Request. WTP to AC. Used by the WTP to report about incoming probe requests
def _handle_probe_request(self, wtp, request): """Handle an incoming PROBE_REQUEST message. Args: request, a PROBE_REQUEST message Returns: None """ if not wtp.connection: LOG.info("Probe request from disconnected WTP %s", wtp.addr) self.stream.close() return if not wtp.port(): LOG.info("WTP %s not ready", wtp.addr) return sta = EtherAddress(request.sta) if sta in RUNTIME.lvaps: return if not RUNTIME.is_allowed(sta): return if RUNTIME.is_denied(sta): return ssid = SSID(request.ssid) if request.ssid == b'': LOG.info("Probe request from %s ssid %s", sta, "Broadcast") else: LOG.info("Probe request from %s ssid %s", sta, ssid) # generate list of available SSIDs ssids = set() for tenant in RUNTIME.tenants.values(): if tenant.bssid_type == T_TYPE_SHARED: continue for wtp_in_tenant in tenant.wtps.values(): if wtp.addr == wtp_in_tenant.addr: ssids.add(tenant.tenant_name) if not ssids: LOG.info("No SSIDs available at this WTP") return # spawn new LVAP LOG.info("Spawning new LVAP %s on %s", sta, wtp.addr) net_bssid = generate_bssid(BASE_MAC, sta) lvap = LVAP(sta, net_bssid, net_bssid) lvap.set_ssids(list(ssids)) # set supported band lvap.supported_band = request.supported_band # Check if block is valid incoming = ResourceBlock(wtp, EtherAddress(request.hwaddr), request.channel, request.band) valid = [block for block in wtp.supports if block == incoming] if not valid: LOG.warning("No valid intersection found. Ignoring request.") return # This will trigger an LVAP ADD message (and REMOVE if necessary) lvap.blocks = valid[0] # save LVAP in the runtime RUNTIME.lvaps[sta] = lvap LOG.info("Sending probe response to %s", lvap.addr) self.send_probe_response(lvap, ssid)
def addr(self, addr): """ Set the address. """ self._addr = EtherAddress(addr)
def loop(self): """ Periodic job. """ # Add callbacks for the new WTPs and LVAPs that # have joined the network since last loop periodic trigger self.wtp_up_initialize() # reset this list self.new_wtps=[] self.lvap_join_initialize() # reset this list self.new_lvaps=[] self.global_window_counter += 1 wtp_assoc_set=[] # find the lvap using sta mac addr. ?? ## fix ## corrected # This is a dictionary of all the lvaps currently in the network. all_lvaps = self.lvaps() # This is the EtherAddress object for the specified mac address. tagged_lvap_etherAddr_obj = EtherAddress(self.tagged_sta_mac_addr) # Proceed further only if the lvap I am interested in following has joined the network if all_lvaps.get(tagged_lvap_etherAddr_obj) is not None : # This is the EtherAddress object for the specified mac address. tagged_lvap = all_lvaps[tagged_lvap_etherAddr_obj] tagged_lvap_curr_assoc_wtp = tagged_lvap.wtp best_target_wtp = tagged_lvap_current_association if self.tagged_lvap_sample_counter >= self.sliding_window_samples : self.dl_meas_prob_good_thput[tagged_lvap_curr_assoc_wtp.addr,tagged_lvap.addr] = \ (sum(i >= self.thput_threshold \ for i in self.dl_meas_thput[tagged_lvap_curr_assoc.addr,tagged_lvap.addr]) /float(self.sliding_window_samples)) #if self.dl_meas_prob_good_thput[tagged_lvap_curr_assoc_wtp.addr,tagged_lvap.addr] < self.tolerance_prob : association_changed_flag = False max_prob_satisfying_qos = self.dl_meas_prob_good_thput[tagged_lvap_curr_assoc_wtp.addr,tagged_lvap.addr] for wtp in self.wtps() : # If it is not then trigger the task of finding a new one, # by iterating through all the association options. # pick the one that is best after iterating through all of them. if wtp.addr != tagged_lvap_curr_assoc_wtp.addr : # Evaluate attainable throughput if tagged sta is moved ot this wtp # All lvaps associated with that wtp for block in wtp.supports: # I am assuming that of all the blocks only 1 block has lvaps on it. # the others will return NOne for lvaps if self.lvaps(block=block) not None: # This is the block on which lvaps are scheduled wtp_assoc_set = copy.copy(self.lvaps(block=block)) wtp_assoc_set.append(tagged_lvap) self.nif_evaluate_stats(wtp.addr, wtp_assoc_set) prob_satisfying_qos = \ (sum(i >= self.thput_threshold \ for i in self.dl_att_thput[wtp.addr,tagged_lvap.addr]) /float(self.sliding_window_samples)) if prob_satisfying_qos > max_prob_satisfying_qos : # After this evaluation I need to see if this association set is a fit for the tagged sta. max_prob_satisfying_qos = prob_satisfying_qos best_target_wtp = wtp association_changed_flag = True # I shall now use this wtp with the least prob of violating # qos and associate the tagged lvap with this wtp. # This is supposed to trigger the handover. if association_changed_flag : tagged_lvap.wtp = wtp_with_min_qos_violation_prob # Reset counters and the measured throughput window since these values cannot be used anymore. self.tagged_lvap_sample_counter = 0 self.dl_meas_thput[tagged_lvap_curr_assoc_wtp.addr, tagged_lvap.addr]=[]
def __parse_vbses_descriptor(self, descriptor): for addr in descriptor['lte']['vbses']: vbs_addr = EtherAddress(addr) if vbs_addr not in self.tenant.vbses: raise KeyError("Unable to find VBS %s" % addr) self.lte['vbses'][vbs_addr] = { 'static-properties': {} } if 'static-properties' in descriptor['lte']['vbses'][addr]: if 'sched_id' in \ descriptor['lte']['vbses'][addr]['static-properties']: sched_id = descriptor['lte']['vbses'][addr] \ ['static-properties']['sched_id'] if not isinstance(sched_id, int): sched_id = int(sched_id) if sched_id not in LTE_SLICE_SCHED.values(): raise ValueError("Invalid LTE slice scheduler") self.lte['vbses'][vbs_addr]['static-properties']['sched_id'] = sched_id if 'rbgs' in \ descriptor['lte']['vbses'][addr]['static-properties']: rbgs = descriptor['lte']['vbses'][addr] \ ['static-properties']['rbgs'] if not isinstance(rbgs, int): rbgs = int(rbgs) self.lte['vbses'][vbs_addr]['static-properties']['rbgs'] = rbgs if 'window' in \ descriptor['lte']['vbses'][addr]['static-properties']: window = descriptor['lte']['vbses'][addr] \ ['static-properties']['window'] if not isinstance(window, int): int(window) self.lte['vbses'][vbs_addr]['static-properties']['window'] = window if 'period' in \ descriptor['lte']['vbses'][addr]['static-properties']: period = descriptor['lte']['vbses'][addr] \ ['static-properties']['period'] if not isinstance(period, int): period = int(period) self.lte['vbses'][vbs_addr]['static-properties']['period'] = period
def _handle_auth_request(self, request): """Handle an incoming AUTH_REQUEST message. Args: request, a AUTH_REQUEST message Returns: None """ wtp_addr = EtherAddress(request.wtp) try: wtp = RUNTIME.wtps[wtp_addr] except KeyError: LOG.info("Auth request from unknown WTP %s", wtp_addr) return if not wtp.connection: LOG.info("Auth request from disconnected WTP %s", wtp_addr) return sta = EtherAddress(request.sta) bssid = EtherAddress(request.bssid) if sta not in RUNTIME.lvaps: LOG.info("Auth request from unknown LVAP %s", sta) return lvap = RUNTIME.lvaps[sta] if not RUNTIME.is_allowed(sta): LOG.info("Auth request from %s ignored (white list)", sta) return if RUNTIME.is_denied(sta): LOG.info("Auth request from %s ignored (black list)", sta) return lvap_bssid = None # the request bssid is the lvap's unique bssid if lvap.net_bssid == bssid: lvap_bssid = lvap.net_bssid # else if is a shared bssid else: shared_tenants = [ x for x in RUNTIME.tenants.values() if x.bssid_type == T_TYPE_SHARED ] wtp = RUNTIME.wtps[wtp_addr] # look for bssid in shared tenants for tenant in shared_tenants: if bssid in tenant.vaps and tenant.vaps[bssid].wtp == wtp: lvap_bssid = bssid break # invalid bssid, ignore request if not lvap_bssid: return # this will trigger an add lvap message to update the bssid lvap.lvap_bssid = lvap_bssid LOG.info("Auth request from %s for BSSID %s, replying", sta, bssid) self.send_auth_response(lvap)
def lvap_addr(self, value): """Set lvap_addr.""" self.__lvap_addr = EtherAddress(value)
def _handle_assoc_request(self, request): """Handle an incoming ASSOC_REQUEST message. Args: request, a ASSOC_REQUEST message Returns: None """ wtp_addr = EtherAddress(request.wtp) try: wtp = RUNTIME.wtps[wtp_addr] except KeyError: LOG.info("Assoc request from unknown WTP %s", wtp_addr) return if not wtp.connection: LOG.info("Assoc request from disconnected WTP %s", wtp_addr) return sta = EtherAddress(request.sta) if sta not in RUNTIME.lvaps: LOG.info("Assoc request from unknown LVAP %s", sta) return lvap = RUNTIME.lvaps[sta] if not RUNTIME.is_allowed(sta): LOG.info("Assoc request from %s ignored (white list)", sta) return if RUNTIME.is_denied(sta): LOG.info("Assoc request from %s ignored (black list)", sta) return ssid = SSID(request.ssid.decode('UTF-8')) bssid = EtherAddress(request.bssid) tenant_name = None # look for ssid in shared tenants for tenant_id in RUNTIME.tenants: tenant = RUNTIME.tenants[tenant_id] if tenant.bssid_type == T_TYPE_UNIQUE: continue if bssid in tenant.vaps and ssid == tenant.tenant_name: tenant_name = tenant.tenant_name # otherwise this must be the lvap unique bssid if lvap.net_bssid == bssid and ssid in lvap.ssids: tenant_name = ssid if not tenant_name: LOG.info("Assoc request sta %s for ssid %s bssid %s, ignoring", lvap.addr, lvap.ssid, lvap.lvap_bssid) return # this will trigger an add lvap message to update the ssid lvap.tenant = RUNTIME.load_tenant(tenant_name) # this will trigger an add lvap message to update the assoc id lvap.assoc_id = self.server.assoc_id LOG.info("Assoc request sta %s ssid %s bssid %s assoc id %u, replying", lvap.addr, lvap.ssid, lvap.lvap_bssid, lvap.assoc_id) self.send_assoc_response(lvap)
def lvap(self, value): self._lvap = EtherAddress(value)
def put(self, *args, **kwargs): """ Set the WTP for a given LVAP, effectivelly hands-over the LVAP to another WTP Args: lvap_id: the lvap address Request: version: the protocol version (1.0) Example URLs: PUT /api/v1/lvaps/11:22:33:44:55:66 """ try: if len(args) != 1: raise ValueError("Invalid URL") request = tornado.escape.json_decode(self.request.body) if "version" not in request: raise ValueError("missing version element") lvap_addr = EtherAddress(args[0]) lvap = RUNTIME.lvaps[lvap_addr] if "blocks" in request: pool = [] for block in request["blocks"]: wtp_addr = EtherAddress(block['wtp']) wtp = RUNTIME.wtps[wtp_addr] hwaddr = EtherAddress(block['hwaddr']) channel = int(block['channel']) band = block['band'] r_block = ResourceBlock(wtp, hwaddr, channel, REVERSE_BANDS[band]) pool.append(r_block) lvap.blocks = pool elif "wtp" in request: wtp_addr = EtherAddress(request['wtp']) wtp = RUNTIME.wtps[wtp_addr] lvap.wtp = wtp if "encap" in request: encap = EtherAddress(request["encap"]) lvap.encap = encap except KeyError as ex: self.send_error(404, message=ex) except ValueError as ex: self.send_error(400, message=ex) self.set_status(204, None)
def addrs(self, addrs): """ Set the address. """ self._addrs = EtherAddress(addrs)
def _trigger_message(self, hdr): if hdr.type == E_TYPE_SINGLE: event = E_SINGLE.parse(self.__buffer[HEADER.sizeof():]) offset = HEADER.sizeof() + E_SINGLE.sizeof() elif hdr.type == E_TYPE_SCHED: event = E_SCHED.parse(self.__buffer[HEADER.sizeof():]) offset = HEADER.sizeof() + E_SCHED.sizeof() elif hdr.type == E_TYPE_TRIG: event = E_TRIG.parse(self.__buffer[HEADER.sizeof():]) offset = HEADER.sizeof() + E_TRIG.sizeof() else: self.log.error("Unknown event %u", hdr.type) return msg_type = event.action if msg_type not in self.server.pt_types: self.log.error("Unknown message type %u", msg_type) return if self.server.pt_types[msg_type]: msg = self.server.pt_types[msg_type].parse(self.__buffer[offset:]) msg_name = self.server.pt_types[msg_type].name addr = EtherAddress(hdr.enbid[2:8]) try: vbs = RUNTIME.vbses[addr] except KeyError: self.log.error("Unknown VBS %s, closing connection", addr) self.stream.close() return if not self.vbs: self.vbs = vbs valid = [EP_ACT_HELLO] if not self.vbs.is_connected() and msg_type not in valid: self.log.info("Got %s message from disconnected VBS %s seq %u", msg_name, addr, hdr.seq) return valid = [EP_ACT_HELLO, EP_ACT_CAPS] if not self.vbs.is_online() and msg_type not in valid: self.log.info("Got %s message from offline VBS %s seq %u", msg_name, addr, hdr.seq) return self.log.info("Got %s message from %s seq %u xid %u", msg_name, self.vbs.addr, hdr.seq, hdr.xid) handler_name = "_handle_%s" % msg_name if hasattr(self, handler_name): handler = getattr(self, handler_name) handler(vbs, hdr, event, msg) if msg_type in self.server.pt_types_handlers: for handler in self.server.pt_types_handlers[msg_type]: handler(vbs, hdr, event, msg)
def handle_response(self, response): """Handle an incoming response message. Args: message, a response message Returns: None """ wtp_addr = EtherAddress(response.wtp) if wtp_addr not in RUNTIME.wtps: return tenant = RUNTIME.tenants[self.tenant_id] if wtp_addr not in tenant.wtps: return self.frames = [] for recv in response.frames: if self.block.band == BT_L20: rate = float(recv[4]) / 2 else: rate = int(recv[4]) if recv[5] == 0x00: pt_type = "MNGT" elif recv[5] == 0x04: pt_type = "CTRL" elif recv[5] == 0x08: pt_type = "DATA" else: pt_type = "UNKN" if recv[6] == 0x00: pt_subtype = "ASSOC_REQ" elif recv[6] == 0x10: pt_subtype = "ASSOC_RESP" elif recv[6] == 0x20: pt_subtype = "AUTH_REQ" elif recv[6] == 0x30: pt_subtype = "AUTH_RESP" elif recv[6] == 0x80: pt_subtype = "BEACON" else: pt_subtype = recv[6] frame = { 'tsft': recv[1], 'seq': recv[2], 'rssi': recv[3], 'rate': rate, 'type': pt_type, 'subtype': pt_subtype, 'length': recv[7] } self.frames.append(frame) self.handle_callback(self)
def _handle_auth_request(self, wtp, request): """Handle an incoming AUTH_REQUEST message. Args: request, a AUTH_REQUEST message Returns: None """ sta = EtherAddress(request.sta) if sta not in RUNTIME.lvaps: self.log.info("Auth request from unknown LVAP %s", sta) return lvap = RUNTIME.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 tenant in RUNTIME.tenants.values(): if tenant.bssid_type == T_TYPE_SHARED: continue bssid = tenant.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 tenant in RUNTIME.tenants.values(): if tenant.bssid_type == T_TYPE_UNIQUE: continue if incoming_bssid in tenant.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_status_lvap(self, wtp, status): """Handle an incoming STATUS_LVAP message. Args: status, a STATUS_LVAP message Returns: None """ if not wtp.connection: LOG.info("Status from disconnected WTP %s", wtp.addr) return sta_addr = EtherAddress(status.sta) set_mask = bool(status.flags.set_mask) lvap = None LOG.info("LVAP status update from %s", sta_addr) # If the LVAP does not exists, then create a new one if sta_addr not in RUNTIME.lvaps: net_bssid_addr = EtherAddress(status.net_bssid) lvap_bssid_addr = EtherAddress(status.lvap_bssid) lvap = LVAP(sta_addr, net_bssid_addr, lvap_bssid_addr) RUNTIME.lvaps[sta_addr] = lvap lvap = RUNTIME.lvaps[sta_addr] # incoming block lvap.supported = ResourcePool() hwaddr = EtherAddress(status.hwaddr) channel = status.channel band = status.band lvap.supported.add(ResourceBlock(lvap, hwaddr, channel, band)) match = wtp.supports & lvap.supported if not match: LOG.error("Incoming block %s is invalid", block) return block = match.pop() # this will try to updated the lvap object with the resource block # coming in this status update message. try: if set_mask: # set downlink+uplink block lvap._downlink.setitem(block, RadioPort(lvap, block)) else: # set uplink only blocks lvap._uplink.setitem(block, RadioPort(lvap, block)) except ValueError: LOG.error("Error while importing block %s, removing.", block) block.radio.connection.send_del_lvap(lvap) return lvap.authentication_state = bool(status.flags.authenticated) lvap.association_state = bool(status.flags.associated) lvap._assoc_id = status.assoc_id lvap._encap = EtherAddress(status.encap) ssids = [SSID(x.ssid) for x in status.ssids] if lvap.ssid: # Raise LVAP leave event self.server.send_lvap_leave_message_to_self(lvap) # removing LVAP from tenant, need first to look for right tenant if lvap.addr in lvap.tenant.lvaps: LOG.info("Removing %s from tenant %s", lvap.addr, lvap.ssid) del lvap.tenant.lvaps[lvap.addr] lvap._tenant = None if ssids[0]: tenant = RUNTIME.load_tenant(ssids[0]) if not tenant: LOG.info("LVAP %s from unknown tenant %s", lvap.addr, ssids[0]) RUNTIME.remove_lvap(lvap.addr) return # setting tenant without seding out add lvap message lvap._tenant = tenant # adding LVAP to tenant LOG.info("Adding %s to tenant %s", lvap.addr, ssids[0]) lvap.tenant.lvaps[lvap.addr] = lvap # Raise LVAP join event self.server.send_lvap_join_message_to_self(lvap) # update remaining ssids lvap._ssids = ssids[1:] # set ports lvap.set_ports() LOG.info("LVAP status %s", lvap)
def _handle_status_lvap(self, wtp, status): """Handle an incoming STATUS_LVAP message. Args: status, a STATUS_LVAP message Returns: None """ sta = EtherAddress(status.sta) # Check if block is valid valid = wtp.get_block(status.hwaddr, status.channel, status.band) if not valid: self.log.warning("No valid intersection found. Removing block.") wtp.connection.send_del_lvap(sta) return # If the LVAP does not exists, then create a new one if sta not in RUNTIME.lvaps: RUNTIME.lvaps[sta] = LVAP(sta, assoc_id=status.assoc_id, state=PROCESS_RUNNING) lvap = RUNTIME.lvaps[sta] # update LVAP params lvap.supported_band = status.supported_band lvap.encap = EtherAddress(status.encap) lvap.authentication_state = bool(status.flags.authenticated) lvap.association_state = bool(status.flags.associated) 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 set_mask = status.flags.set_mask # received downlink block but a different downlink block is already # present, delete before going any further if set_mask and lvap.blocks[0] and lvap.blocks[0] != valid[0]: lvap.blocks[0].radio.connection.send_del_lvap(sta) if set_mask: lvap._downlink = valid[0] else: lvap._uplink.append(valid[0]) # if this is not a DL+UL block then stop here if not set_mask: return # if an SSID is set and the incoming SSID is different from the # current one then raise an LVAP leave event and remove LVAP from the # current SSID if lvap.ssid and ssid != lvap.ssid: self.server.send_lvap_leave_message_to_self(lvap) del lvap.tenant.lvaps[lvap.addr] lvap.ssid = None # if the incoming ssid is not none then raise an lvap join event if ssid: lvap.ssid = ssid lvap.tenant.lvaps[lvap.addr] = lvap self.server.send_lvap_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_hello(self, hello): """Handle an incoming HELLO message. Args: hello, a HELLO message Returns: None """ wtp_addr = EtherAddress(hello.wtp) try: wtp = RUNTIME.wtps[wtp_addr] except KeyError: LOG.info("Hello from unknown WTP (%s)", wtp_addr) return LOG.info("Hello from %s seq %u", self.addr[0], hello.seq) # compute delta if not new connection if wtp.connection: delta = time.time() - wtp.last_seen_ts # uplink ul_bytes = hello.uplink_bytes - wtp.uplink_bytes wtp.uplink_bytes_per_second = int(ul_bytes / delta) * 8 # downlink dl_bytes = hello.downlink_bytes - wtp.downlink_bytes wtp.downlink_bytes_per_second = int(dl_bytes / delta) * 8 # If this is a new connection, then send caps request if not wtp.connection: # set wtp before connection because it is used when the # connection attribute of the PNFDev object is set self.wtp = wtp wtp.connection = self # Update WTP params wtp.period = hello.period wtp.last_seen = hello.seq wtp.uplink_bytes = hello.uplink_bytes wtp.downlink_bytes = hello.downlink_bytes wtp.last_seen_ts = time.time() # Upon connection to the controller, the WTP must be provided # with the list of shared VAP for tenant in RUNTIME.tenants.values(): # tenant does not use shared VAPs if tenant.bssid_type == T_TYPE_UNIQUE: continue # wtp not in this tenant if wtp_addr not in tenant.wtps: continue tenant_id = tenant.tenant_id tokens = [tenant_id.hex[0:12][i:i + 2] for i in range(0, 12, 2)] base_bssid = EtherAddress(':'.join(tokens)) for block in wtp.supports: net_bssid = generate_bssid(base_bssid, block.hwaddr) # vap has already been created if net_bssid in RUNTIME.tenants[tenant_id].vaps: continue vap = VAP(net_bssid, block, wtp, tenant) self.send_add_vap(vap) RUNTIME.tenants[tenant_id].vaps[net_bssid] = vap
def put(self, *args, **kwargs): """ Set the WTP for a given LVAP, effectivelly hands-over the LVAP to another WTP Args: pool_id: the pool address lvap_id: the lvap address Request: version: the protocol version (1.0) Example URLs: PUT /api/v1/pools/52313ecb-9d00-4b7d-b873-b55d3d9ada26/lvaps/11:22:33:44:55:66 """ try: if len(args) != 2: raise ValueError("Invalid URL") request = tornado.escape.json_decode(self.request.body) if "version" not in request: raise ValueError("missing version element") tenant_id = uuid.UUID(args[0]) lvap_addr = EtherAddress(args[1]) tenant = RUNTIME.tenants[tenant_id] lvap = tenant.lvaps[lvap_addr] if "wtp" in request: wtp_addr = EtherAddress(request['wtp']) wtp = tenant.wtps[wtp_addr] lvap.wtp = wtp elif "blocks" in request: pool = [] for block in request["blocks"]: wtp_addr = EtherAddress(block['wtp']) wtp = RUNTIME.wtps[wtp_addr] hwaddr = EtherAddress(block['hwaddr']) channel = int(block['channel']) band = int(block['band']) r_block = ResourceBlock(wtp, hwaddr, channel, band) pool.append(r_block) lvap.blocks = pool if "encap" in request: encap = EtherAddress(request["encap"]) lvap.encap = encap except KeyError as ex: self.send_error(404, message=ex) except ValueError as ex: self.send_error(400, message=ex) self.set_status(204, None)
def _handle_probe_request(self, request): """Handle an incoming PROBE_REQUEST message. Args: request, a PROBE_REQUEST message Returns: None """ wtp_addr = EtherAddress(request.wtp) try: wtp = RUNTIME.wtps[wtp_addr] except KeyError: LOG.info("Probe request from unknown WTP (%s)", wtp_addr) return if not wtp.connection: LOG.info("Probe request from disconnected WTP %s", wtp_addr) return sta = EtherAddress(request.sta) if sta in RUNTIME.lvaps: return if not RUNTIME.is_allowed(sta): return if RUNTIME.is_denied(sta): return ssid = SSID(request.ssid) if request.ssid == b'': LOG.info("Probe request from %s ssid %s", sta, "Broadcast") else: LOG.info("Probe request from %s ssid %s", sta, ssid) # generate list of available SSIDs ssids = set() for tenant in RUNTIME.tenants.values(): if tenant.bssid_type == T_TYPE_SHARED: continue for wtp_in_tenant in tenant.wtps.values(): if wtp_addr == wtp_in_tenant.addr: ssids.add(tenant.tenant_name) if not ssids: LOG.info("No SSIDs available at this WTP") return # spawn new LVAP LOG.info("Spawning new LVAP %s on %s", sta, wtp.addr) net_bssid = generate_bssid(BASE_MAC, sta) lvap = LVAP(sta, net_bssid, net_bssid) lvap.set_ssids(ssids) RUNTIME.lvaps[sta] = lvap # TODO: This should be built starting from the probe request lvap.supports.add(ResourceBlock(lvap, sta, 1, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 2, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 3, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 4, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 5, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 6, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 7, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 8, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 9, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 10, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 11, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 36, BT_L20)) lvap.supports.add(ResourceBlock(lvap, sta, 48, BT_L20)) # This will trigger an LVAP ADD message (and REMOVE if necessary) requested = ResourcePool() hwaddr = EtherAddress(request.hwaddr) channel = request.channel band = request.band requested.add(ResourceBlock(wtp, hwaddr, channel, band)) lvap.scheduled_on = wtp.supports & requested LOG.info("Sending probe response to %s", lvap.addr) self.send_probe_response(lvap)
from empower.lvapp import PROBE_RESPONSE from empower.core.lvap import LVAP from empower.core.networkport import NetworkPort from empower.core.vap import VAP from empower.lvapp import PT_ADD_VAP from empower.lvapp import ADD_VAP from empower.core.tenant import T_TYPE_SHARED from empower.core.tenant import T_TYPE_UNIQUE from empower.core.utils import generate_bssid from empower.main import RUNTIME import empower.logger LOG = empower.logger.get_logger() BASE_MAC = EtherAddress("00:1b:b3:00:00:00") class LVAPPConnection(object): """LVAPP Connection. Represents a connection to a WTP (Wireless Termination Point) using the LVAP Protocol. One LVAPPConnection object is created for every WTP in the network. The object implements the logic for handling incoming messages. The currently supported messages are: Hello. WTP to AC. Used as keepalive between the WTP and the AC Probe Request. WTP to AC. Used by the WTP to report about incoming probe requests
def mcast(self, value): """Set the mcast Address.""" self._mcast = EtherAddress(value)