def _handle_status_vap(cls, wtp, status): """Handle an incoming STATUS_VAP message. Args: status, a STATUS_VAP message Returns: None """ if not wtp.connection: LOG.info("VAP Status from disconnected WTP %s", wtp.addr) return net_bssid_addr = EtherAddress(status.net_bssid) ssid = SSID(status.ssid) tenant = RUNTIME.load_tenant(ssid) if not tenant: LOG.info("VAP %s from unknown tenant %s", net_bssid_addr, ssid) return incoming = ResourceBlock(wtp, EtherAddress(status.hwaddr), status.channel, status.band) LOG.info("VAP status update from %s", net_bssid_addr) # If the VAP does not exists, then create a new one if net_bssid_addr not in tenant.vaps: vap = VAP(net_bssid_addr, incoming, wtp, tenant) tenant.vaps[net_bssid_addr] = vap vap = tenant.vaps[net_bssid_addr] LOG.info("VAP status %s", vap)
def _handle_caps(self, wtp, caps): """Handle an incoming CAPS message. Args: caps, a CAPS message Returns: None """ LOG.info("Received caps from %s", wtp.addr) for block in caps.blocks: hwaddr = EtherAddress(block[0]) r_block = ResourceBlock(wtp, hwaddr, block[1], block[2]) wtp.supports.add(r_block) for port in caps.ports: iface = port[2].decode("utf-8").strip('\0') network_port = NetworkPort(dpid=wtp.addr, hwaddr=EtherAddress(port[0]), port_id=int(port[1]), iface=iface) wtp.ports[network_port.port_id] = network_port # WTP can be considered as available once the empower0 port has been # added to the OVS if wtp.port(): self.send_register_message_to_self()
def block(self, value): if isinstance(value, ResourceBlock): self._block = value elif isinstance(value, dict): wtp = RUNTIME.wtps[EtherAddress(value['wtp'])] if 'hwaddr' not in value: raise ValueError("Missing field: hwaddr") if 'channel' not in value: raise ValueError("Missing field: channel") if 'band' not in value: raise ValueError("Missing field: band") if 'wtp' not in value: raise ValueError("Missing field: wtp") # Check if block is valid incoming = ResourceBlock(wtp, EtherAddress(value['hwaddr']), int(value['channel']), int(value['band'])) match = [block for block in wtp.supports if block == incoming] if not match: raise ValueError("No block specified") if len(match) > 1: raise ValueError("More than one block specified") self._block = match[0]
def _handle_caps_response(self, caps): """Handle an incoming CAPS message.""" for block in caps.blocks: self.device.blocks[block.block_id] = \ ResourceBlock(self.device, block.block_id, EtherAddress(block.hwaddr), block.channel, block.band) # set state to online super()._handle_caps_response(caps) # fetch active lvaps self.send_lvap_status_request() # fetch active vaps self.send_vap_status_request() # fetch active traffic rules self.send_slice_status_request() # fetch active tramission policies self.send_tx_policy_status_request() # send vaps self.update_vaps() # send slices self.update_slices()
def _handle_caps(cls, caps): """Handle an incoming CAPS message. Args: caps, a CAPS message Returns: None """ wtp_addr = EtherAddress(caps.wtp) try: wtp = RUNTIME.wtps[wtp_addr] except KeyError: LOG.info("Caps response from unknown WTP (%s)", wtp_addr) return LOG.info("Received caps response from %s", wtp_addr) for block in caps.blocks: hwaddr = EtherAddress(block[0]) r_block = ResourceBlock(wtp, hwaddr, block[1], block[2]) wtp.supports.add(r_block) for port in caps.ports: iface = port[2].decode("utf-8").strip('\0') network_port = NetworkPort(dpid=wtp.addr, hwaddr=EtherAddress(port[0]), port_id=int(port[1]), iface=iface) wtp.ports[network_port.port_id] = network_port
def handle_response(self, message): """ Handle an incoming BUSYNESS_TRIGGER message. Args: message, a BUSYNESS_TRIGGER message Returns: None """ wtp_addr = EtherAddress(message.wtp) if wtp_addr not in RUNTIME.wtps: return wtp = RUNTIME.wtps[wtp_addr] if wtp_addr not in RUNTIME.tenants[self.tenant_id].wtps: return hwaddr = EtherAddress(message.hwaddr) channel = message.channel band = message.band incoming = ResourceBlock(wtp, hwaddr, channel, band) match = [block for block in wtp.supports if block == incoming] self.event = \ {'block': matches[0], 'timestamp': datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ"), 'current': message.current / 180.0} self.handle_callback(self)
def handle_response(self, message): """ Handle an incoming RSSI_TRIGGER message. Args: message, a RSSI_TRIGGER message Returns: None """ wtp_addr = EtherAddress(message.wtp) if wtp_addr not in RUNTIME.wtps: return wtp = RUNTIME.wtps[wtp_addr] if wtp_addr not in RUNTIME.tenants[self.tenant_id].wtps: return incoming = ResourcePool() hwaddr = EtherAddress(message.hwaddr) channel = message.channel band = message.band incoming.add(ResourceBlock(wtp, hwaddr, channel, band)) matches = wtp.supports & incoming self.event = \ {'block': matches.pop(), 'timestamp': datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%fZ"), 'current': message.current} self.handle_callback(self)
def _handle_caps(self, wtp, caps): """Handle an incoming CAPS message. Args: caps, a CAPS message Returns: None """ dpid = DPID(caps['dpid']) if dpid not in RUNTIME.datapaths: RUNTIME.datapaths[dpid] = Datapath(dpid) wtp.datapath = RUNTIME.datapaths[dpid] for block in caps.blocks: hwaddr = EtherAddress(block[0]) r_block = ResourceBlock(wtp, hwaddr, block[1], block[2]) wtp.supports.add(r_block) for port in caps.ports: hwaddr = EtherAddress(port[0]) port_id = int(port[1]) iface = port[2].decode("utf-8").strip('\0') if port_id not in wtp.datapath.network_ports: network_port = NetworkPort(dp=wtp.datapath, port_id=port_id, hwaddr=hwaddr, iface=iface) wtp.datapath.network_ports[port_id] = network_port # set state to online wtp.set_online() # fetch active lvaps self.send_lvap_status_request() # fetch active vaps self.send_vap_status_request() # fetch active traffic rules self.send_slice_status_request() # fetch active tramission policies self.send_transmission_policy_status_request() # send vaps self.update_vaps() # send slices self.update_slices()
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 _handle_status_vap(cls, status): """Handle an incoming STATUS_VAP message. Args: status, a STATUS_VAP message Returns: None """ wtp_addr = EtherAddress(status.wtp) try: wtp = RUNTIME.wtps[wtp_addr] except KeyError: LOG.info("VAP Status from unknown WTP %s", wtp_addr) return if not wtp.connection: LOG.info("VAP Status from disconnected WTP %s", wtp_addr) return net_bssid_addr = EtherAddress(status.net_bssid) ssid = SSID(status.ssid) tenant_id = None for tenant in RUNTIME.tenants.values(): if tenant.tenant_name == ssid: tenant_id = tenant.tenant_id break if not tenant_id: LOG.info("VAP %s from unknown tenant %s", net_bssid_addr, ssid) return tenant = RUNTIME.tenants[tenant_id] vap = None hwaddr = EtherAddress(status.hwaddr) block = ResourceBlock(wtp, hwaddr, status.channel, status.band) ssid = status.ssid LOG.info("VAP %s status update block %s", net_bssid_addr, block) # If the VAP does not exists, then create a new one if net_bssid_addr not in tenant.vaps: tenant.vaps[net_bssid_addr] = \ VAP(net_bssid_addr, block, wtp, tenant) vap = tenant.vaps[net_bssid_addr] LOG.info("VAP status %s", vap)
def handle_response(self, response): """Handle an incoming poller response message. Args: message, a poller response message Returns: None """ wtp_addr = EtherAddress(response.wtp) if wtp_addr not in RUNTIME.wtps: return wtp = RUNTIME.wtps[wtp_addr] hwaddr = EtherAddress(response.hwaddr) block = ResourceBlock(wtp, hwaddr, response.channel, response.band) incoming = ResourcePool() incoming.add(block) matching = (wtp.supports & incoming).pop() if not matching: return # handle the message setattr(self.block, self.MODULE_NAME, CQM()) map_entry = getattr(self.block, self.MODULE_NAME) for entry in response.img_entries: addr = EtherAddress(entry[0]) if not addr.match(self.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 self.handle_callback(self)
def _handle_status_port(cls, status): """Handle an incoming PORT message. Args: status, a STATUS_PORT 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) hwaddr = EtherAddress(status.hwaddr) block = ResourceBlock(wtp, hwaddr, status.channel, status.band) # 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() LOG.info("Port status from %s, station %s", wtp_addr, sta_addr) tx_policy = block.tx_policies[sta_addr] tx_policy._mcs = set([float(x) / 2 for x in status.mcs]) tx_policy._rts_cts = int(status.rts_cts) tx_policy._mcast = int(status.tx_mcast) tx_policy._ur_count = int(status.ur_mcast_count) tx_policy._no_ack = bool(status.flags.no_ack) LOG.info("Port status %s", tx_policy)
def _handle_status_port(self, status): """Handle an incoming PORT message. Args: status, a STATUS_PORT 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) hwaddr = EtherAddress(status.hwaddr) block = ResourceBlock(wtp, hwaddr, status.channel, status.band) LOG.info("Port status from %s", sta_addr) try: lvap = RUNTIME.lvaps[sta_addr] except KeyError: LOG.error("Invalid LVAP %s, ignoring", sta_addr) return try: port = lvap.downlink[block] except KeyError: LOG.error("Invalid Block %s, ignoring", block) return port._no_ack = bool(status.flags.no_ack) port._rts_cts = int(status.rts_cts) port._mcs = set([float(x) / 2 for x in status.mcs]) LOG.info("Port status %s", port)
def _handle_caps(self, wtp, caps): """Handle an incoming CAPS message. Args: caps, a CAPS message Returns: None """ LOG.info("Received caps from %s", wtp.addr) for block in caps.blocks: hwaddr = EtherAddress(block[0]) r_block = ResourceBlock(wtp, hwaddr, block[1], block[2]) wtp.supports.add(r_block) for port in caps.ports: iface = port[2].decode("utf-8").strip('\0') network_port = NetworkPort(dpid=wtp.addr, hwaddr=EtherAddress(port[0]), port_id=int(port[1]), iface=iface) wtp.ports[network_port.port_id] = network_port # set state to online wtp.set_online() # fetch active lvaps self.send_lvap_status_request() # fetch active vaps self.send_vap_status_request() # fetch active traffic rules self.send_traffic_rule_status_request() # fetch active transmission rules self.send_port_status_request() # send vaps self.send_vaps()
def _handle_status_traffic_rule(self, wtp, status): """Handle an incoming STATUS_TRAFFIC_RULE message. Args: status, a STATUS_TRAFFIC_RULE message Returns: None """ if not wtp.connection: LOG.info("Traffic rule status from disconnected WTP %s", wtp.addr) return quantum = status.quantum amsdu_aggregation = bool(status.flags.amsdu_aggregation) dscp = "{0:#0{1}x}".format(status.dscp, 4) ssid = SSID(status.ssid) tenant = RUNTIME.load_tenant(ssid) if not tenant: LOG.info("Traffic rule status from unknown tenant %s", ssid) return incoming = ResourceBlock(wtp, EtherAddress(status.hwaddr), status.channel, status.band) valid = [block for block in self.wtp.supports if block == incoming] if not valid: LOG.warning("No valid intersection found. Ignoring request.") return block = valid[0] trq = block.traffic_rule_queues[(ssid, dscp)] trq._quantum = quantum trq._amsdu_aggregation = amsdu_aggregation LOG.info("Transmission rule status %s", trq)
def _handle_status_port(cls, wtp, status): """Handle an incoming PORT message. Args: status, a STATUS_PORT message Returns: None """ if not wtp.connection: LOG.info("Status from disconnected WTP %s", wtp.addr) return sta_addr = EtherAddress(status.sta) # incoming block incoming = ResourceBlock(wtp, EtherAddress(status.hwaddr), status.channel, status.band) valid = [block for block in wtp.supports if block == incoming] if not valid: LOG.error("Incoming block %s is invalid", incoming) return block = valid[0] LOG.info("Port status from %s, station %s", wtp.addr, sta_addr) tx_policy = block.tx_policies[sta_addr] tx_policy._mcs = set([float(x) / 2 for x in status.mcs]) tx_policy._ht_mcs = set([int(x) for x in status.ht_mcs]) tx_policy._rts_cts = int(status.rts_cts) tx_policy._mcast = int(status.tx_mcast) tx_policy._ur_count = int(status.ur_mcast_count) tx_policy._no_ack = bool(status.flags.no_ack) LOG.info("Port status %s", tx_policy)
def block(self, value): """Set block.""" if isinstance(value, ResourceBlock): self._block = value elif isinstance(value, dict): wtp = RUNTIME.wtps[EtherAddress(value['wtp'])] if 'hwaddr' not in value: raise ValueError("Missing field: hwaddr") if 'channel' not in value: raise ValueError("Missing field: channel") if 'band' not in value: raise ValueError("Missing field: band") if 'wtp' not in value: raise ValueError("Missing field: wtp") incoming = ResourcePool() block = ResourceBlock(wtp, EtherAddress(value['hwaddr']), int(value['channel']), int(value['band'])) incoming.add(block) match = wtp.supports & incoming if not match: raise ValueError("No block specified") if len(match) > 1: raise ValueError("More than one block specified") self._block = match.pop()
def post(self, *args, **kwargs): """ Create a new module. Args: [0]: tenant_id Request: version: the protocol version (1.0) Example URLs: POST /api/v1/tenants/EmPOWER/<module> """ try: if len(args) != 1: raise ValueError("Invalid URL") tenant_id = uuid.UUID(args[0]) request = tornado.escape.json_decode(self.request.body) if "version" not in request: raise ValueError("missing version element") if "wtp" not in request: raise ValueError("missing wtp element") if "band" not in request: raise ValueError("missing band element") if "channel" not in request: raise ValueError("missing channel element") del request['version'] request['tenant_id'] = tenant_id request['module_type'] = self.worker.MODULE_NAME request['worker'] = self.worker wtp_addr = EtherAddress(request['wtp']) wtp = RUNTIME.tenants[tenant_id].wtps[wtp_addr] channel = int(request['channel']) band = int(request['band']) del request['wtp'] del request['channel'] del request['band'] request['block'] = ResourceBlock(wtp, channel, band) module = self.worker.add_module(**request) self.set_header("Location", "/api/v1/tenants/%s/%s/%s" % (module.tenant_id, self.worker.MODULE_NAME, module.module_id)) self.set_status(201, None) except KeyError as ex: self.send_error(404, message=ex) except ValueError as ex: self.send_error(400, message=ex)
def get_block(self, hwaddr, channel, band): """Look for block.""" incoming = ResourceBlock(self, EtherAddress(hwaddr), channel, band) return [block for block in self.supports if block == incoming]
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 # received downlink block but a different downlink block is already # present, delete before going any further if set_mask and lvap._downlink and lvap._downlink != valid[0]: lvap._downlink.radio.connection.send_del_lvap(lvap) if set_mask: lvap._downlink = valid[0] else: lvap._uplink.append(valid[0]) # update ports if not lvap.ports: lvap.ports[0] = VirtualPort(virtual_port_id=0) lvap.ports[0].poas.append(wtp.port()) # 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 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 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 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) wtp: the new wtp address Example URLs: PUT /api/v1/pools/EmPOWER/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") if "wtp" not in request and "scheduled_on" not in request and \ "encap" not in request: raise ValueError("missing wtp/scheduled_on 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 if "scheduled_on" in request: pool = ResourcePool() for block in request["scheduled_on"]: wtp_addr = EtherAddress(block['wtp']) wtp = RUNTIME.wtps[wtp_addr] channel = int(block['channel']) band = int(block['band']) rb = ResourceBlock(wtp, channel, band) pool.add(rb) lvap.scheduled_on = 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, 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)) RUNTIME.lvaps[sta] = lvap # This will trigger an LVAP ADD message (and REMOVE if necessary) lvap.supported = ResourcePool() hwaddr = EtherAddress(request.hwaddr) channel = request.channel band = request.band lvap.supported.add(ResourceBlock(lvap, hwaddr, channel, band)) lvap.scheduled_on = wtp.supports & lvap.supported LOG.info("Sending probe response to %s", lvap.addr) self.send_probe_response(lvap)
def _handle_assoc_request(self, wtp, request): """Handle an incoming ASSOC_REQUEST message. Args: request, a ASSOC_REQUEST message Returns: None """ 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) # update supported blocks field lvap.supported = ResourcePool() hwaddr = EtherAddress(request.hwaddr) channel = request.channel band = request.band lvap.supported.add(ResourceBlock(lvap, hwaddr, channel, band)) # 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 _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 _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)
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_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 _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)