def put(self, *args, **kwargs): """Update an account. Args: [0]: the username Request: version: protocol version (1.0) username: username password: password role: tole name: name surname: surname email: email Example URLs: PUT /api/v1/accounts/test { "version" : 1.0, "username" : "foo", "password" : "foo", "role" : "user", "name" : "foo", "surname" : "foo", "email" : "*****@*****.**" } """ RUNTIME.update_account(args[0], kwargs)
def delete(self, *args, **kwargs): """ Unload a component. Args: tenant_id: the tenant id component_id: the id of a component istance Example URLs: DELETE /api/v1/tenants/52313ecb-9d00-4b7d-b873-b55d3d9ada26/<id> """ try: if len(args) != 2: raise ValueError("Invalid url") tenant_id = UUID(args[0]) app_id = args[1] RUNTIME.unregister_app(tenant_id, app_id) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(204, None)
def delete(self, *args, **kwargs): """ Delete a tenant request. Args: tenant_id: network name of a tenant Example URLs: PUT /api/v1/pending/52313ecb-9d00-4b7d-b873-b55d3d9ada26 """ try: if len(args) == 0: pendings = RUNTIME.load_pending_tenants() for pending in pendings: RUNTIME.reject_tenant(pending.tenant_id) else: tenant_id = UUID(args[0]) RUNTIME.reject_tenant(tenant_id) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(204, None)
def delete(self, *args, **kwargs): """ Unload a component. Args: component_id: the id of a component istance Example URLs: DELETE /api/v1/components/component """ try: if len(args) != 1: raise ValueError("Invalid url") RUNTIME.unregister(args[0]) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(204, None)
def delete(self, *args, **kwargs): """ Unload a component. Args: username: the username Example URLs: DELETE /api/v1/accounts/test """ try: if len(args) != 1: raise ValueError("Invalid url") RUNTIME.remove_account(args[0]) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(204, None)
def _handle_ue_ho_response(self, vbs, hdr, event, ho): """Handle an incoming UE_HO_RESPONSE message. Args: ho, a UE_HO_RESPONSE message Returns: None """ addr = hex_to_ether(ho.origin_eNB) origin_vbs = RUNTIME.vbses[addr] ue = RUNTIME.find_ue_by_rnti(ho.origin_rnti, ho.origin_pci, origin_vbs) if event.op == EP_OPERATION_SUCCESS: # UE was removed from source eNB if ue.is_ho_in_progress_removing(): ue.set_ho_in_progress_adding() return # UE was added to target eNB if ue.is_ho_in_progress_adding(): ue._cell = vbs.get_cell_by_pci(hdr.cellid) ue.rnti = ho.target_rnti ue.set_active() return self.log.error("Error while performing handover") RUNTIME.remove_ue(ue.ue_id)
def _on_disconnect(self): """ Handle WTP disconnection """ if not self.wtp: return self.log.info("WTP disconnected: %s", self.wtp.addr) # remove hosted lvaps for lvap in list(RUNTIME.lvaps.values()): wtps = [x.radio for x in lvap.blocks] if self.wtp in wtps: RUNTIME.remove_lvap(lvap.addr) # remove hosted vaps for tenant_id in list(RUNTIME.tenants.keys()): for vap_id in list(RUNTIME.tenants[tenant_id].vaps.keys()): vap = RUNTIME.tenants[tenant_id].vaps[vap_id] if vap.block.radio == self.wtp: self.log.info("Deleting VAP: %s", vap.bssid) del RUNTIME.tenants[tenant_id].vaps[vap.bssid] # reset state self.wtp.set_disconnected() self.wtp.last_seen = 0 self.wtp.connection = None self.wtp.supports = set() self.wtp.datapath = None self.wtp = None
def post(self, *args, **kwargs): """Create a new account. Request: version: protocol version (1.0) username: username password: password role: tole name: name surname: surname email: email Example URLs: POST /api/v1/accounts { "version" : 1.0, "username" : "foo", "password" : "foo", "role" : "user", "name" : "foo", "surname" : "foo", "email" : "*****@*****.**" } """ RUNTIME.create_account(kwargs['username'], kwargs['password'], kwargs['role'], kwargs['name'], kwargs['surname'], kwargs['email'])
def post(self, *args, **kwargs): """Add a component. Request: version: protocol version (1.0) component: the component id params: dictionary of parametes supported by the component as reported by the GET request Example URLs: POST /api/v1/components { "version" : 1.0, "component" : "empower.apps.mobilitymanager.mobilitymanager" "params": { "every": 1000 } } """ func = getattr(import_module(kwargs["component"]), "launch") if "params" in kwargs: RUNTIME.register(kwargs["component"], func, kwargs["params"]) else: RUNTIME.register(kwargs["component"], func, dict())
def get(self, *args, **kwargs): """ Lists all the tenants requested. Returns 404 if the requested tenant does not exists. Args: tenant_id: network name of a tenant Example URLs: GET /api/v1/pending GET /api/v1/pending/TenantName """ try: if len(args) > 1: raise ValueError("Invalid url") if len(args) == 0: user = self.get_argument("user", default=None) if user: pendings = RUNTIME.load_pending_tenants(user) else: pendings = RUNTIME.load_pending_tenants() self.write(json.dumps(pendings, cls=EmpowerEncoder)) else: tenant_id = UUID(args[0]) pending = RUNTIME.load_pending_tenant(tenant_id) self.write(json.dumps(pending, cls=EmpowerEncoder)) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex)
def post(self, *args, **kwargs): """ Add a component. Args: [0]: the tenant id Request: version: protocol version (1.0) component: module name params: dictionary of parametes supported by the component as reported by the GET request Example URLs: POST /api/v1/components { "version" : 1.0, "component" : "empower.lvapp.bin_counter.bin_counter" "params": {} } """ func = getattr(import_module(kwargs["component"]), "launch") kwargs["params"]["tenant_id"] = UUID(args[0]) RUNTIME.register_app(kwargs["component"], func, kwargs["params"])
def _on_disconnect(self): """ Handle WTP disconnection """ if not self.wtp: return LOG.info("WTP disconnected: %s", self.wtp.addr) # remove hosted lvaps for addr in list(RUNTIME.lvaps.keys()): lvap = RUNTIME.lvaps[addr] dl_wtps = [block.radio for block in lvap.downlink.keys()] ul_wtps = [block.radio for block in lvap.uplink.keys()] # in case the downlink went down, the remove also the uplinks if self.wtp in dl_wtps: RUNTIME.remove_lvap(lvap.addr) elif self.wtp in ul_wtps: LOG.info("Deleting LVAP (UL): %s", lvap.addr) lvap.clear_uplink() # remove hosted vaps for tenant_id in RUNTIME.tenants.keys(): for vap_id in list(RUNTIME.tenants[tenant_id].vaps.keys()): vap = RUNTIME.tenants[tenant_id].vaps[vap_id] if vap.wtp == self.wtp: LOG.info("Deleting VAP: %s", vap.net_bssid) del RUNTIME.tenants[tenant_id].vaps[vap.net_bssid] # reset state self.wtp.last_seen = 0 self.wtp.connection = None self.wtp.ports = {} self.wtp.supports = set() self.wtp = None
def _on_disconnect(self): """ Handle WTP disconnection """ if not self.wtp: return LOG.info("WTP disconnected: %s", self.wtp.addr) # remove hosted lvaps for addr in list(RUNTIME.lvaps.keys()): lvap = RUNTIME.lvaps[addr] dl_wtps = [block.radio for block in lvap.downlink.keys()] ul_wtps = [block.radio for block in lvap.uplink.keys()] # in case the downlink went down, the remove also the uplinks if self.wtp in dl_wtps: RUNTIME.remove_lvap(lvap.addr) elif self.wtp in ul_wtps: LOG.info("Deleting LVAP (UL): %s", lvap.addr) lvap.clear_uplink() # remove hosted vaps for tenant_id in RUNTIME.tenants.keys(): for vap_id in list(RUNTIME.tenants[tenant_id].vaps.keys()): vap = RUNTIME.tenants[tenant_id].vaps[vap_id] if vap.wtp == self.wtp: LOG.info("Deleting VAP: %s", vap.net_bssid) del RUNTIME.tenants[vap.tenant_id].vaps[vap.net_bssid] # reset state self.wtp.last_seen = 0 self.wtp.connection = None self.wtp.ports = {} self.wtp.supports = ResourcePool() self.wtp = None
def _handle_auth_request(self, wtp, request): """Handle an incoming AUTH_REQUEST message. Args: request, a AUTH_REQUEST message Returns: None """ 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 post(self, *args, **kwargs): """Create a new tenant. Args: [0], the tenant id Request: version: protocol version (1.0) owner: the username of the requester tenant_name: the network name desc: a description for the new tenant bssid_type: shared or unique plmn_id: the PLMN id """ bssid_type = kwargs["bssid_type"] \ if "bssid_type" in kwargs else T_TYPE_UNIQUE plmn_id = PLMNID(kwargs["plmn_id"]) if "plmn_id" in kwargs else None tenant_id = UUID(args[0]) if args else None RUNTIME.add_tenant(kwargs['owner'], kwargs['desc'], kwargs['tenant_name'], bssid_type, tenant_id, plmn_id) self.set_header("Location", "/api/v1/tenants/%s" % tenant_id)
def get(self, *args, **kwargs): """ Lists all the tenants requested. Returns 404 if the requested tenant does not exists. Args: tenant_id: network name of a tenant Example URLs: GET /api/v1/pending GET /api/v1/pending/TenantName """ try: if len(args) > 1: raise ValueError("Invalid url") if len(args) == 0: user = self.get_argument("user", default=None) if user: pendings = RUNTIME.load_pending_tenants(user) else: pendings = RUNTIME.load_pending_tenants() self.write_as_json(pendings) else: tenant_id = UUID(args[0]) pending = RUNTIME.load_pending_tenant(tenant_id) self.write_as_json(pending) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex)
def delete(self, *args, **kwargs): """ Delete a tenant. Args: tenant_id: network name of a tenant Request: version: protocol version (1.0) Example URLs: DELETE /api/v1/tenants/52313ecb-9d00-4b7d-b873-b55d3d9ada26 """ try: if len(args) == 0: for tenant in list(RUNTIME.tenants.keys()): RUNTIME.remove_tenant(tenant) else: tenant_id = UUID(args[0]) RUNTIME.remove_tenant(tenant_id) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(204, None)
def _running_disconnecting(self): self._state = PROCESS_DISCONNECTING from empower.main import RUNTIME # remove UE from the RUNTIME RUNTIME.remove_ue(self.ue_id)
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')) matches = [x for x in RUNTIME.tenants.values() if SSID(x.tenant_name) == ssid] if not matches: LOG.info("Assoc request to unknown SSID: %s ", request.ssid) return # this will trigger an add lvap message to update the ssid lvap.ssid = ssid # 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 assoc id %u ssid %s, sending response", lvap.addr, lvap.assoc_id, lvap.ssid) self.send_assoc_response(lvap)
def _handle_ue_report_response(self, vbs, hdr, event, ue_report): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ incoming = [] for ue in ue_report.ues: if RUNTIME.find_ue_by_rnti(ue.rnti, ue.pci, vbs): continue plmn_id = PLMNID(ue.plmn_id[1:].hex()) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unable to find PLMN id %s", plmn_id) continue if vbs.addr not in tenant.vbses: self.log.info("VBS %s not in PLMN id %s", vbs.addr, plmn_id) continue cell = vbs.get_cell_by_pci(ue.pci) if not cell: self.log.info("PCI %u not found", u.pci) continue if ue.imsi != 0: ue_id = uuid.uuid5(uuid.NAMESPACE_DNS, str(ue.imsi)) else: ue_id = uuid.uuid4() ue = UE(ue_id, ue.imsi, ue.rnti, cell, plmn_id, tenant) ue.set_active() RUNTIME.ues[ue.ue_id] = ue tenant.ues[ue.ue_id] = ue incoming.append(ue.ue_id) self.server.send_ue_join_message_to_self(ue) # check for leaving UEs for ue_id in list(RUNTIME.ues.keys()): if RUNTIME.ues[ue_id].vbs != vbs: continue if not RUNTIME.ues[ue_id].is_active(): self.log.info("Handover in progress for %u, ignoring", ue_id) continue if ue_id not in incoming: RUNTIME.remove_ue(ue_id)
def delete(self, *args, **kwargs): """Unload a component. Args: component_id: the id of a component istance Example URLs: DELETE /api/v1/components/component """ RUNTIME.unregister(args[0])
def put(self, *args, **kwargs): """ Update an account. Args: username: the username Request: version: protocol version (1.0) username: username password: password role: tole name: name surname: surname email: email Example URLs: PUT /api/v1/accounts/test { "version" : 1.0, "username" : "foo", "password" : "foo", "role" : "user", "name" : "foo", "surname" : "foo", "email" : "*****@*****.**" } """ 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") del request['version'] RUNTIME.update_account(args[0], request) except ValueError as ex: self.send_error(400, message=ex) except AttributeError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(204, None)
def _handle_ue_report_response(self, vbs, hdr, event, msg): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ for raw_entry in msg.options: if raw_entry.type not in UE_REPORT_TYPES: self.log.warning("Unknown options %u", raw_entry) continue prop = UE_REPORT_TYPES[raw_entry.type].name option = UE_REPORT_TYPES[raw_entry.type].parse(raw_entry.data) self.log.warning("Processing options %s", prop) if raw_entry.type == EP_UE_REPORT_IDENTITY: plmn_id = PLMNID(option.plmn_id) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unknown tenant %s", plmn_id) continue # TODO: Implement fallback mechanism IMSI->TMSI->RNTI ue_id = uuid.UUID(int=option.imsi) # UE already known, update its parameters if ue_id in RUNTIME.ues: ue = RUNTIME.ues[ue_id] ue.rnti = option.rnti # UE is disconnecting if option.state == 1: RUNTIME.remove_ue(ue_id) else: cell = vbs.cells[hdr.cellid] ue = UE(ue_id, option.rnti, option.imsi, option.timsi, cell, tenant) RUNTIME.ues[ue.ue_id] = ue tenant.ues[ue.ue_id] = ue # UE is connected if option.state == 0: self.server.send_ue_join_message_to_self(ue)
def delete(self, *args, **kwargs): """Unload a component. Args: [0]: the username Example URLs: DELETE /api/v1/accounts/test """ RUNTIME.remove_account(args[0])
def delete(self, *args, **kwargs): """ Delete entry from ACL. Args: [0]: the station address Example URLs: DELETE /api/v1/allow/11:22:33:44:55:66 """ RUNTIME.remove_allowed(EtherAddress(args[0]))
def _handle_ue_report_response(self, vbs, hdr, event, ue_report): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ ues = {u.imsi: u for u in ue_report.ues} # check for new UEs for u in ues.values(): # UE already known if u.imsi in RUNTIME.ues: continue plmn_id = PLMNID(u.plmn_id[1:].hex()) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unable to find PLMN id %s", plmn_id) continue if vbs.addr not in tenant.vbses: self.log.info("VBS %s not in PLMN id %s", vbs.addr, plmn_id) continue cell = None for c in vbs.cells: if c.pci == u.pci: cell = c break if not cell: self.log.info("PCI %u not found", u.pci) continue ue = UE(u.imsi, u.rnti, cell, plmn_id, tenant) ue.set_active() RUNTIME.ues[u.imsi] = ue tenant.ues[u.imsi] = ue self.server.send_ue_join_message_to_self(ue) # check for leaving UEs for imsi in list(RUNTIME.ues.keys()): if RUNTIME.ues[imsi].vbs != vbs: continue if imsi not in ues: RUNTIME.remove_ue(imsi)
def delete(self, *args, **kwargs): """Delete a tenant. Args: [0]: network name of a tenant Example URLs: DELETE /api/v1/tenants DELETE /api/v1/tenants/52313ecb-9d00-4b7d-b873-b55d3d9ada26 """ RUNTIME.remove_tenant(UUID(args[0]))
def put(self, *args, **kwargs): """ Update an account. Args: username: the username Request: version: protocol version (1.0) username: username password: password role: tole name: name surname: surname email: email Example URLs: PUT /api/v1/accounts/test { "version" : 1.0, "username" : "foo", "password" : "foo", "role" : "user", "name" : "foo", "surname" : "foo", "email" : "*****@*****.**" } """ 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") del request['version'] RUNTIME.update_account(args[0], request) except ValueError as ex: self.send_error(400, message=ex) except AttributeError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(204, None)
def delete(self, *args, **kwargs): """Unload a component. Args: [0]: the component id Example URLs: DELETE /api/v1/components/ empower.apps.mobilitymanager.mobilitymanager """ RUNTIME.unregister(args[0])
def delete(self, *args, **kwargs): """ Unload a component. Args: tenant_id: the tenant id component_id: the id of a component istance Example URLs: DELETE /api/v1/tenants/52313ecb-9d00-4b7d-b873-b55d3d9ada26/<id> """ RUNTIME.unregister_app(UUID(args[0]), args[1])
def put(self, *args, **kwargs): """Update a component. Args: [0]: the component id Request: version: protocol version (1.0) params: dictionary of parametes supported by the component as reported by the GET request Example URLs: PUT /api/v1/components/empower.apps.mobilitymanager.mobilitymanager { "version" : 1.0, "params": { "every": 1000 } } """ components = RUNTIME.load_main_components() component = components[args[0]] for param in kwargs['params']: if "params" not in component or param not in component['params']: msg = "Cannot set %s on compoment %s" % (param, args[0]) raise ValueError(msg) setattr(component, param, kwargs['params'][param])
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_status_vap(self, wtp, status): """Handle an incoming STATUS_VAP message. Args: status, a STATUS_VAP message Returns: None """ bssid = EtherAddress(status.bssid) ssid = SSID(status.ssid) tenant = RUNTIME.load_tenant(ssid) if not tenant: self.log.info("VAP %s from unknown tenant %s", bssid, ssid) return # 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 VAP.") wtp.connection.send_del_vap(bssid) return # If the VAP does not exists, then create a new one if bssid not in tenant.vaps: vap = VAP(bssid, valid, tenant) tenant.vaps[bssid] = vap vap = tenant.vaps[bssid] self.log.info("VAP status %s", vap)
def send_del_ran_mac_slice_request(self, cell, plmn_id, dscp): """Send an DEL_SLICE message. """ tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) # check if tenant is valid if not tenant: self.log.info("Unknown tenant %s", plmn_id) return # check if slice is valid if dscp in tenant.slices: # UEs already present in the slice must be moved to the default slice # before deleting the current slice for ue in list(RUNTIME.ues.values()): if self.vbs == ue.vbs and dscp == ue.slice: ue.slice = DSCP("0x00") else: self.log.warning("DSCP %s not found. Removing slice.", dscp) # Then proceed to remove the current slice msg = Container(plmn_id=plmn_id.to_raw(), dscp=dscp.to_raw(), padding=b'\x00\x00\x00', length=REM_RAN_MAC_SLICE_REQUEST.sizeof()) self.send_message(msg, E_TYPE_SINGLE, EP_ACT_RAN_MAC_SLICE, REM_RAN_MAC_SLICE_REQUEST, opcode=EP_OPERATION_REM, cellid=cell.pci)
def post(self, *args, **kwargs): """ Create a new tenant. Args: None Request: version: protocol version (1.0) owner: the username of the requester tenant_id: the network name desc: a description for the new tenant Example URLs: POST /api/v1/tenants """ 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") if "owner" not in request: raise ValueError("missing owner element") if "desc" not in request: raise ValueError("missing desc element") if "tenant_name" not in request: raise ValueError("missing tenant_name element") if len(args) == 1: tenant_id = UUID(args[0]) else: tenant_id = None tenant_id = \ RUNTIME.add_tenant(request['owner'], request['desc'], request['tenant_name'], tenant_id) self.set_header("Location", "/api/v1/tenants/%s" % tenant_id) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(201, None)
def _on_disconnect(self): """Handle VBSP disconnection.""" if not self.vbs: return LOG.info("VBS disconnected: %s", self.vbs.addr) # remove hosted ues for addr in list(RUNTIME.ues.keys()): ue = RUNTIME.ues[addr] if ue.vbs == self.vbs: RUNTIME.remove_ue(ue.addr) # reset state self.vbs.last_seen = 0 self.vbs.connection = None self.vbs.ues = {} self.vbs.period = 0
def post(self): username = self.get_argument("username", "") password = self.get_argument("password", "") if RUNTIME.check_permission(username, password): self.set_secure_cookie("user", username) self.redirect(self.get_argument("next", "/")) else: error_msg = "Login incorrect." self.redirect("/auth/login/" + "?error=" + tornado.escape.url_escape(error_msg))
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) 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 LOG.info("Auth request from %s, sending auth response", sta) self.send_auth_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 # 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_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 _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._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 post(self, *args, **kwargs): """ Create a new tenant request. Args: None Request: version: protocol version (1.0) owner: the username of the requester tenant_id: the network name desc: a description for the new tenant bssid_type: shared or unique Example URLs: POST /api/v1/pending """ 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") if "desc" not in request: raise ValueError("missing desc element") if "tenant_name" not in request: raise ValueError("missing tenant_name element") if "bssid_type" not in request: bssid_type = T_TYPE_UNIQUE else: bssid_type = request['bssid_type'] if bssid_type not in T_TYPES: raise ValueError("invalid bssid_type %s" % bssid_type) if len(args) == 1: tenant_id = UUID(args[0]) else: tenant_id = None tenant_name = SSID(request['tenant_name']) RUNTIME.request_tenant(self.account.username, request['desc'], tenant_name, bssid_type, tenant_id) self.set_header("Location", "/api/v1/pendig/%s" % tenant_id) except KeyError as ex: self.send_error(404, message=ex) except ValueError as ex: self.send_error(400, message=ex) self.set_status(201, None)
def _handle_UEs_id_repl(self, main_msg): """Handle an incoming UEs ID reply. Args: message, a emage_msg containing UE IDs (RNTIs) Returns: None """ active_ues = {} inactive_ues = {} event_type = main_msg.WhichOneof("event_types") msg = protobuf_to_dict(main_msg) ues_id_msg_repl = msg[event_type]["mUEs_id"]["repl"] if ues_id_msg_repl["status"] != configs_pb2.CREQS_SUCCESS: return # List of active UEs if "active_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["active_ue_id"]: active_ues[ue["rnti"]] = {} if "imsi" in ue: active_ues[ue["rnti"]]["imsi"] = ue["imsi"] else: active_ues[ue["rnti"]]["imsi"] = None if "plmn_id" in ue: active_ues[ue["rnti"]]["plmn_id"] = ue["plmn_id"] else: active_ues[ue["rnti"]]["plmn_id"] = None # List of inactive UEs if "inactive_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["inactive_ue_id"]: inactive_ues[ue["rnti"]] = {} if "imsi" in ue: inactive_ues[ue["rnti"]]["imsi"] = ue["imsi"] else: inactive_ues[ue["rnti"]]["imsi"] = None if "plmn_id" in ue: inactive_ues[ue["rnti"]]["plmn_id"] = ue["plmn_id"] else: inactive_ues[ue["rnti"]]["plmn_id"] = None for rnti in active_ues: ue_id = hex_to_ether(rnti) if ue_id not in RUNTIME.ues: ue_id = hex_to_ether(rnti) imsi = active_ues[ue["rnti"]]["imsi"] new_ue = UE(ue_id, imsi, self.vbs) RUNTIME.ues[ue_id] = new_ue ue = RUNTIME.ues[ue_id] plmn_id = int(active_ues[rnti]["plmn_id"]) if not ue.plmn_id and plmn_id: # setting tenant ue.tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if ue.tenant: # adding UE to tenant LOG.info("Adding %s to tenant %s", ue.addr, ue.tenant.plmn_id) ue.tenant.ues[ue.addr] = ue # Raise UE join self.server.send_ue_join_message_to_self(ue) if ue.plmn_id and not plmn_id: # removing UE from tenant LOG.info("Removing %s from tenant %s", ue.addr, ue.tenant.plmn_id) del ue.tenant.ues[ue.addr] # Raise UE leave self.server.send_ue_leave_message_to_self(ue) # setting tenant ue.tenant = None existing_ues = [] existing_ues.extend(RUNTIME.ues.keys()) for ue_id in existing_ues: if ether_to_hex(ue_id) not in active_ues: RUNTIME.remove_ue(ue_id)
def prepare(self): """Prepare to handler reply.""" self.set_header('Content-Type', 'application/json') if not self.RIGHTS[self.request.method]: return auth_header = self.request.headers.get('Authorization') if auth_header is None or not auth_header.startswith('Basic '): self.set_header('WWW-Authenticate', 'Basic realm=Restricted') self.send_error(401) return auth_bytes = bytes(auth_header[6:], 'utf-8') auth_decoded = base64.b64decode(auth_bytes).decode() username, password = auth_decoded.split(':', 2) # account does not exists if not RUNTIME.check_permission(username, password): self.send_error(401) return self.account = RUNTIME.get_account(username) if self.account.role in self.RIGHTS[self.request.method]: if self.account.role == ROLE_ADMIN: return if self.request.uri.startswith("/api/v1/accounts"): pattern = re.compile("/api/v1/accounts/([a-zA-Z0-9:-]*)/?") match = pattern.match(self.request.uri) if match and match.group(1): if match.group(1) in RUNTIME.accounts: account = RUNTIME.accounts[match.group(1)] if self.account.username == account.username: return else: self.send_error(401) return return if self.request.uri.startswith("/api/v1/pending"): pattern = re.compile("/api/v1/pending/([a-zA-Z0-9-]*)/?") match = pattern.match(self.request.uri) if match and match.group(1): try: tenant_id = UUID(match.group(1)) except ValueError: self.send_error(400) return pending = RUNTIME.load_pending_tenant(tenant_id) if pending: if self.account.username == pending.owner: return self.send_error(401) return return if self.request.uri.startswith("/api/v1/tenants"): pattern = re.compile("/api/v1/tenants/([a-zA-Z0-9-]*)/?") match = pattern.match(self.request.uri) if match and match.group(1): tenant_id = UUID(match.group(1)) if tenant_id in RUNTIME.tenants: tenant = RUNTIME.tenants[tenant_id] if self.account.username == tenant.owner: return self.send_error(401) return return self.send_error(401) return
def post(self, *args, **kwargs): """ Create a new account. Request: version: protocol version (1.0) username: username password: password role: tole name: name surname: surname email: email Example URLs: POST /api/v1/accounts { "version" : 1.0, "username" : "foo", "password" : "foo", "role" : "user", "name" : "foo", "surname" : "foo", "email" : "*****@*****.**" } """ try: if len(args) != 0: raise ValueError("Invalid url") request = tornado.escape.json_decode(self.request.body) if "version" not in request: raise ValueError("missing version element") if "username" not in request: raise ValueError("missing username element") if "password" not in request: raise ValueError("missing password element") if "role" not in request: raise ValueError("missing role element") if "name" not in request: raise ValueError("missing name element") if "surname" not in request: raise ValueError("missing surname element") if "email" not in request: raise ValueError("missing email element") if request['role'] not in [ROLE_ADMIN, ROLE_USER]: raise ValueError("Invalid role %s" % request['role']) RUNTIME.create_account(request['username'], request['password'], request['role'], request['name'], request['surname'], request['email']) except ValueError as ex: self.send_error(400, message=ex) except KeyError as ex: self.send_error(404, message=ex) self.set_status(201, None)
def _handle_UEs_id_repl(self, main_msg): """Handle an incoming UEs ID reply. Args: message, a emage_msg containing UE IDs (RNTIs) Returns: None """ active_ues = {} inactive_ues = {} event_type = main_msg.WhichOneof("event_types") msg = protobuf_to_dict(main_msg) ues_id_msg_repl = msg[event_type]["mUEs_id"]["repl"] if ues_id_msg_repl["status"] != configs_pb2.CREQS_SUCCESS: return # List of active UEs if "active_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["active_ue_id"]: active_ues[(self.vbs.addr, ue["rnti"])] = {} if "imsi" in ue: active_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = ue["imsi"] else: active_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = None if "plmn_id" in ue: active_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = \ ue["plmn_id"] else: active_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = None # List of inactive UEs if "inactive_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["inactive_ue_id"]: inactive_ues[(self.vbs.addr, ue["rnti"])] = {} if "imsi" in ue: inactive_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = \ ue["imsi"] else: inactive_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = None if "plmn_id" in ue: inactive_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = \ ue["plmn_id"] else: inactive_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = None for vbs_id, rnti in active_ues.keys(): ue_id = (self.vbs.addr, rnti) if ue_id not in RUNTIME.ues: new_ue = UE(ue_id, ue_id[1], self.vbs) RUNTIME.ues[ue_id] = new_ue ue = RUNTIME.ues[ue_id] imsi = active_ues[ue_id]["imsi"] plmn_id = int(active_ues[ue_id]["plmn_id"]) # Setting IMSI of UE ue.imsi = imsi if not ue.plmn_id and plmn_id: # Setting tenant ue.tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if ue.tenant: # Adding UE to tenant LOG.info("Adding %s to tenant %s", ue.addr, ue.tenant.plmn_id) ue.tenant.ues[ue.addr] = ue # Raise UE join self.server.send_ue_join_message_to_self(ue) # Create a trigger for reporting RRC measurements config. from empower.ue_confs.ue_rrc_meas_confs import ue_rrc_meas_confs conf_req = { "event_type": "trigger" } ue_rrc_meas_confs(tenant_id=ue.tenant.tenant_id, vbs=ue.vbs.addr, ue=ue.rnti, conf_req=conf_req) if ue.plmn_id and not plmn_id: # Raise UE leave self.server.send_ue_leave_message_to_self(ue) # Removing UE from tenant LOG.info("Removing %s from tenant %s", ue.addr, ue.tenant.plmn_id) del ue.tenant.ues[ue.addr] # Resetting tenant ue.tenant = None existing_ues = [] existing_ues.extend(RUNTIME.ues.keys()) for ue_addr in existing_ues: if ue_addr not in active_ues: RUNTIME.remove_ue(ue_addr)