def handle_ncqm_response(self, response, wtp, _):
        """Handle NCQM_RESPONSE message."""

        block = wtp.blocks[response.iface_id]
        block.ncqm = {}

        for entry in response.entries:
            addr = EtherAddress(entry['addr'])
            block.ncqm[addr] = {
                'addr': addr,
                'last_rssi_std': entry['last_rssi_std'],
                'last_rssi_avg': entry['last_rssi_avg'],
                'last_packets': entry['last_packets'],
                'hist_packets': entry['hist_packets'],
                'mov_rssi': entry['mov_rssi']
            }

        if wtp.addr not in self.ncqm:
            self.ncqm[wtp.addr] = {}
        self.ncqm[wtp.addr][block.block_id] = block.ncqm
        self.ucqm[wtp.addr][block.block_id]['timestamp'] = datetime.utcnow()

        # handle callbacks
        self.handle_callbacks()
Beispiel #2
0
    def _handle_vap_status_response(self, status):
        """Handle an incoming STATUS_VAP message."""

        bssid = EtherAddress(status.bssid)
        ssid = SSID(status.ssid)

        project = self.manager.projects_manager.load_project_by_ssid(ssid)

        if not project:
            self.log.warning("Unable to find SSID %s", ssid)
            self.send_del_vap(bssid)
            return

        # If the VAP does not exists, then create a new one
        if bssid not in self.manager.vaps:

            incoming = self.device.blocks[status.iface_id]

            self.manager.vaps[bssid] = VAP(bssid, incoming,
                                           project.wifi_props.ssid)

        vap = self.manager.vaps[bssid]

        self.log.info("VAP status: %s", vap)
    def mcast_ip_to_ether(cls, ip_mcast_addr):
        """Transform an IP multicast address into an Ethernet one."""

        if ip_mcast_addr is None:
            return '\x00' * 6

        # The first 24 bits are fixed according to class D IP
        # and IP multicast address convenctions
        mcast_base = '01:00:5e'

        # The 23 low order bits are mapped.
        ip_addr_bytes = str(ip_mcast_addr).split('.')

        # The first IP byte is not use,
        # and only the last 7 bits of the second byte are used.
        second_byte = int(ip_addr_bytes[1]) & 127
        third_byte = int(ip_addr_bytes[2])
        fourth_byte = int(ip_addr_bytes[3])

        mcast_upper = format(second_byte, '02x') + ':' + \
            format(third_byte, '02x') + ':' + \
            format(fourth_byte, '02x')

        return EtherAddress(mcast_base + ':' + mcast_upper)
Beispiel #4
0
    def _handle_tx_policy_status_response(self, status):
        """Handle an incoming TX_POLICY_STATUS_RESPONSE message."""

        block = self.device.blocks[status.iface_id]
        addr = EtherAddress(status.sta)

        if addr in self.manager.lvaps:
            lvap = self.manager.lvaps[addr]
        else:
            lvap = None

        if addr not in block.tx_policies:
            block.tx_policies[addr] = TxPolicy(addr, block, lvap)

        txp = block.tx_policies[addr]

        txp.set_mcs([float(x) / 2 for x in status.mcs])
        txp.set_ht_mcs([int(x) for x in status.mcs_ht])
        txp.set_rts_cts(status.rts_cts)
        txp.set_max_amsdu_len(status.max_amsdu_len)
        txp.set_mcast(status.tx_mcast)
        txp.set_no_ack(status.flags.no_ack)

        self.log.info("TX policy status %s", txp)
Beispiel #5
0
    def get(self, *args, **kwargs):
        """List devices.

        Args:

            [0]: the device address (optional)

        Example URLs:

            GET /api/v1/wtps

            [
                {
                    "addr": "00:0D:B9:2F:56:64",
                    "blocks": {},
                    "connection": null,
                    "desc": "PC Engines ALIX 2D",
                    "last_seen": 0,
                    "last_seen_ts": "1970-01-01T01:00:00.000000Z",
                    "period": 0,
                    "state": "disconnected"
                }
            ]

            GET /api/v1/wtps/00:0D:B9:2F:56:64 (disconnected)

            {
                "addr": "00:0D:B9:2F:56:64",
                "blocks": {},
                "connection": null,
                "desc": "PC Engines ALIX 2D",
                "last_seen": 0,
                "last_seen_ts": "1970-01-01T01:00:00.000000Z",
                "period": 0,
                "state": "disconnected"
            }

            GET /api/v1/wtps/00:0D:B9:2F:56:64 (connected)

            {
                "addr": "00:0D:B9:30:3E:18",
                "blocks": {
                    "0": {
                        "addr": "00:0D:B9:30:3E:18",
                        "band": "HT20",
                        "channel": 36,
                        "ht_supports": [
                            0,
                            1,
                            2,
                            3,
                            4,
                            5,
                            6,
                            7,
                            8,
                            9,
                            10,
                            11,
                            12,
                            13,
                            14,
                            15
                        ],
                        "hwaddr": "04:F0:21:09:F9:9E",
                        "supports": [
                            6,
                            9,
                            12,
                            18,
                            24,
                            36,
                            48,
                            54
                        ],
                        "tx_policies": {
                            "60:F4:45:D0:3B:FC": {
                                "addr": "60:F4:45:D0:3B:FC",
                                "ht_mcs": [
                                    0,
                                    1,
                                    2,
                                    3,
                                    4,
                                    5,
                                    6,
                                    7,
                                    8,
                                    9,
                                    10,
                                    11,
                                    12,
                                    13,
                                    14,
                                    15
                                ],
                                "max_amsdu_len": 3839,
                                "mcast": "legacy",
                                "mcs": [
                                    6.0,
                                    9.0,
                                    12.0,
                                    18.0,
                                    24.0,
                                    36.0,
                                    48.0,
                                    54.0
                                ],
                                "no_ack": false,
                                "rts_cts": 2436,
                                "ur_count": 3
                            }
                        }
                    },
                    "1": {
                        "addr": "00:0D:B9:30:3E:18",
                        "band": "HT20",
                        "channel": 6,
                        "ht_supports": [
                            0,
                            1,
                            2,
                            3,
                            4,
                            5,
                            6,
                            7,
                            8,
                            9,
                            10,
                            11,
                            12,
                            13,
                            14,
                            15
                        ],
                        "hwaddr": "D4:CA:6D:14:C2:09",
                        "supports": [
                            1,
                            2,
                            5,
                            6,
                            9,
                            11,
                            12,
                            18,
                            24,
                            36,
                            48,
                            54
                        ],
                        "tx_policies": {}
                    }
                },
                "connection": {
                    "addr": [
                        "192.168.1.9",
                        46066
                    ]
                },
                "desc": "PC Engines ALIX 2D",
                "last_seen": 8560,
                "last_seen_ts": "2019-08-23T13:09:43.140533Z",
                "period": 0,
                "state": "online"
            }
        """

        return self.service.devices \
            if not args else self.service.devices[EtherAddress(args[0])]
    def get(self, *args, **kwargs):
        """List the LVAPs.

        Args:

            [0]: the lvap address (optional)

        Example URLs:

            GET /api/v1/lvaps

            [
                {
                    "addr": "60:F4:45:D0:3B:FC",
                    "assoc_id": 732,
                    "association_state": false,
                    "authentication_state": false,
                    "blocks": [
                        ...
                    ],
                    "bssid": null,
                    "encap": "00:00:00:00:00:00",
                    "ht_caps": true,
                    "ht_caps_info": {
                        "DSSS_CCK_Mode_in_40_MHz": false,
                        "Forty_MHz_Intolerant": false,
                        "HT_Delayed_Block_Ack": false,
                        "HT_Greenfield": false,
                        "LDPC_Coding_Capability": true,
                        "L_SIG_TXOP_Protection_Support": false,
                        "Maximum_AMSDU_Length": false,
                        "Reserved": false,
                        "Rx_STBC": 0,
                        "SM_Power_Save": 3,
                        "Short_GI_for_20_MHz": true,
                        "Short_GI_for_40_MHz": true,
                        "Supported_Channel_Width_Set": true,
                        "Tx_STBC": false
                    },
                    "networks": [
                        [
                            "52:31:3E:D0:3B:FC",
                            "EmPOWER"
                        ]
                    ],
                    "pending": [],
                    "ssid": null,
                    "state": "running",
                    "wtp": {
                        ...
                    }
                }
            ]

            GET /api/v1/lvaps/60:F4:45:D0:3B:FC

            {
                "addr": "60:F4:45:D0:3B:FC",
                "assoc_id": 732,
                "association_state": false,
                "authentication_state": false,
                "blocks": [
                    ...
                ],
                "bssid": null,
                "encap": "00:00:00:00:00:00",
                "ht_caps": true,
                "ht_caps_info": {
                    "DSSS_CCK_Mode_in_40_MHz": false,
                    "Forty_MHz_Intolerant": false,
                    "HT_Delayed_Block_Ack": false,
                    "HT_Greenfield": false,
                    "LDPC_Coding_Capability": true,
                    "L_SIG_TXOP_Protection_Support": false,
                    "Maximum_AMSDU_Length": false,
                    "Reserved": false,
                    "Rx_STBC": 0,
                    "SM_Power_Save": 3,
                    "Short_GI_for_20_MHz": true,
                    "Short_GI_for_40_MHz": true,
                    "Supported_Channel_Width_Set": true,
                    "Tx_STBC": false
                },
                "networks": [
                    [
                        "52:31:3E:D0:3B:FC",
                        "EmPOWER"
                    ]
                ],
                "pending": [],
                "ssid": null,
                "state": "running",
                "wtp": {
                    ...
                }
            }
        """

        return self.service.lvaps \
            if not args else self.service.lvaps[EtherAddress(args[0])]
Beispiel #7
0
    def get_prefix(self):
        """Return tenant prefix."""

        tokens = [self.project_id.hex[0:12][i:i + 2] for i in range(0, 12, 2)]
        return EtherAddress(':'.join(tokens))
 def decreaseQuantum(self, slc, wtp, ratesProm):
     res = False
     self.decreased_quantums = ""
     updated_slice = {}
     # para todos los lvaps en el wtp
     for sta in self.context.lvaps:
         lvap = self.context.lvaps[sta]
         if lvap.wtp != None and lvap.wtp.addr == wtp.to_str():
             lvap_slice = self.getSliceLvap(sta)
             if not (self.change_quantum[lvap_slice][wtp]):
                 promised_rate = ratesProm[lvap_slice]
                 lvap_rate = self.getLVAPRateMBits(sta.to_str())
                 # si al menos un lvap tiene mayor rate al prometido y el quantum de esa slice en el wtp es mayor al minimo, le saco recursos
                 if lvap_rate > promised_rate:
                     actual_slice = self.context.wifi_slices[str(
                         lvap_slice)]
                     wtp_quantum = actual_slice.properties['quantum']
                     if EtherAddress(wtp) in actual_slice.devices:
                         wtp_quantum = actual_slice.devices[wtp]['quantum']
                     if wtp_quantum > self.quantum_min:
                         res = True
                         self.change_quantum[lvap_slice][wtp] = True
                         updated_slice = {
                             'slice_id': actual_slice.slice_id,
                             'properties': {
                                 'amsdu_aggregation':
                                 actual_slice.
                                 properties['amsdu_aggregation'],
                                 'quantum':
                                 actual_slice.properties['quantum'],
                                 'sta_scheduler':
                                 actual_slice.properties['sta_scheduler']
                             },
                             'devices': actual_slice.devices
                         }
                         addr = EtherAddress(wtp)
                         if addr not in updated_slice['devices']:
                             self.decreased_quantums = self.decreased_quantums + "// S-" + lvap_slice + "--" + str(
                                 updated_slice['properties']['quantum']
                             ) + "->" + str(
                                 updated_slice['properties']['quantum'] -
                                 updated_slice['properties']['quantum'] *
                                 self.quantum_decrease)
                             updated_slice['devices'][addr] = {
                                 'amsdu_aggregation':
                                 actual_slice.
                                 properties['amsdu_aggregation'],
                                 'quantum':
                                 actual_slice.properties['quantum'] -
                                 actual_slice.properties['quantum'] *
                                 self.quantum_decrease,
                                 'sta_scheduler':
                                 actual_slice.properties['sta_scheduler']
                             }
                         else:
                             self.decreased_quantums = self.decreased_quantums + "// S-" + lvap_slice + "--" + str(
                                 updated_slice['devices'][addr]['quantum']
                             ) + "->" + str(
                                 updated_slice['devices'][addr]['quantum'] -
                                 updated_slice['devices'][addr]['quantum'] *
                                 self.quantum_decrease)
                             updated_slice['devices'][addr][
                                 'quantum'] = updated_slice['devices'][
                                     addr]['quantum'] - updated_slice[
                                         'devices'][addr][
                                             'quantum'] * self.quantum_decrease
                         self.context.upsert_wifi_slice(**updated_slice)
     #return updated_slice
     return res
    def try_handover(self, sta, slc, rate, ratesProm, actual_rate):
        posibles_handovers = []
        lvap = self.context.lvaps[EtherAddress(sta)]
        blocks = self.blocks().sort_by_rssi(lvap.addr)

        def filterBlocks(block):
            if block.ucqm[lvap.addr][
                    'mov_rssi'] > self.RSSI_min and block.hwaddr.to_str(
                    ) != lvap.blocks[0].hwaddr.to_str():
                return True
            else:
                return False

        # Filtramos los wtp que tengan malo RSSI
        filtered_blocks = list(filter(filterBlocks, blocks))
        # obtengo el uso del wtp actual
        query = 'select * from wifi_channel_stats where wtp=\'' + lvap.wtp.addr.to_str(
        ) + '\' and block_id=\'' + str(
            lvap.blocks[0].block_id) + '\' and time > now() - ' + str(
                int(self.every / 1000)) + 's;'
        result = self.query(query)
        current_channel_stats = list(result.get_points())
        current_usage = 0
        for current_stats in current_channel_stats:
            current_usage += current_stats[
                'tx']  # + current_stats['rx'] + current_stats['ed']
        current_usage = current_usage / len(current_channel_stats)
        # obtengo historial de handovers para verificar ping pong
        query = 'select * from lvaps_handover where sta=\'' + sta + '\' and time > now() - ' + str(
            int(self.every / 1000) * 10) + 's;'
        result = self.query(query)
        handover_list = list(result.get_points())
        for block in filtered_blocks:
            query = 'select * from wifi_channel_stats where wtp=\'' + block.wtp.addr.to_str(
            ) + '\' and block_id=\'' + str(
                block.block_id) + '\' and time > now() - ' + str(
                    int(self.every / 1000)) + 's;'
            result = self.query(query)
            channel_stats = list(result.get_points())
            usage = 0
            for stats in channel_stats:
                usage += stats['tx']  #+ stats['rx'] + stats['ed']
            usage = usage / len(channel_stats)
            # si el uso del wtp es menor al actual, lo agrego como posible handover
            if usage * 1.1 < current_usage and self.wtp_handovers[
                    block.wtp.addr] < self.max_handovers and not (
                        self.ping_pong(handover_list, block.wtp.addr)):
                posibles_handovers.append({'block': block, 'usage': usage})
        if len(posibles_handovers) > 0:
            # Ordeno los bloques por usage asi me quedo con el que tenga menos
            posibles_handovers.sort(key=lambda x: x['usage'])
            # escribo en logger
            self.write_log(
                slc, sta, "H", lvap.blocks[0].wtp.addr.to_str() + "->" +
                posibles_handovers[0]['block'].wtp.addr.to_str(),
                "Usage new WTP: " + str(posibles_handovers[0]['usage']))
            # Do Handover
            lvap.blocks = posibles_handovers[0]['block']
            self.wtp_handovers[posibles_handovers[0]['block'].wtp.addr] += 1
            # guardar cambios
            # generate data points
            points = []
            timestamp = datetime.utcnow()
            fields = {"wtp": posibles_handovers[0]['block'].wtp.addr}
            tags = {"sta": sta}
            sample = {
                "measurement": 'lvaps_handover',
                "tags": tags,
                "time": timestamp,
                "fields": fields
            }
            points.append(sample)
            # save to db
            self.write_points(points)
            return True
        else:
            # No encontre WTP con uso menor al actual, entonces me fijo si algun wtp tiene lvaps con rate mayor al prometido
            for block in filtered_blocks:
                extra_rate = 0
                for sta2 in self.context.lvaps:
                    lvap = self.context.lvaps[sta2]
                    if lvap.wtp != None and lvap.wtp.addr == block.wtp.addr:
                        lvap_slice = self.getSliceLvap(sta2)
                        promised_rate = ratesProm[lvap_slice]
                        lvap_rate = self.getLVAPRateMBits(sta2.to_str())
                        if (lvap_rate - promised_rate) > 0:
                            extra_rate += (lvap_rate - promised_rate)
                if extra_rate > 0 and (
                        extra_rate >= (actual_rate * 1.2)
                        or extra_rate >= rate) and self.wtp_handovers[
                            block.wtp.addr] < self.max_handovers and not (
                                self.ping_pong(handover_list, block.wtp.addr)):
                    posibles_handovers.append({
                        'block': block,
                        'extra_rate': extra_rate
                    })
            if len(posibles_handovers) > 0:
                # Ordeno los bloques por rate extra asi me quedo con el que tenga mas
                posibles_handovers.sort(key=lambda x: x['extra_rate'])
                # escribo en logger
                self.write_log(
                    slc, sta, "H", lvap.blocks[0].wtp.addr.to_str() + "->" +
                    posibles_handovers[0]['block'].wtp.addr.to_str(),
                    "Extra rate new WTP: " +
                    str(posibles_handovers[0]['extra_rate']))
                # Do Handover
                lvap.blocks = posibles_handovers[-1]['block']
                self.wtp_handovers[posibles_handovers[-1]
                                   ['block'].wtp.addr] += 1
                # guardar cambios
                # generate data points
                points = []
                timestamp = datetime.utcnow()
                fields = {"wtp": posibles_handovers[-1]['block'].wtp.addr}
                tags = {"sta": sta}
                sample = {
                    "measurement": 'lvaps_handover',
                    "tags": tags,
                    "time": timestamp,
                    "fields": fields
                }
                points.append(sample)
                # save to db
                self.write_points(points)
                return True
            else:
                return False
    def _handle_lvap_status_response(self, status):
        """Handle an incoming LVAP_STATUS_RESPONSE message."""

        sta = EtherAddress(status.sta)

        # If the LVAP does not exists, then create a new one
        if sta not in self.manager.lvaps:
            self.manager.lvaps[sta] = \
                LVAP(sta, assoc_id=status.assoc_id, state=PROCESS_RUNNING)

        lvap = self.manager.lvaps[sta]

        # update LVAP params
        lvap.encap = EtherAddress(status.encap)
        lvap.authentication_state = bool(status.flags.authenticated)
        lvap.association_state = bool(status.flags.associated)
        lvap.ht_caps = bool(status.flags.ht_caps)
        lvap.ht_caps_info = dict(status.ht_caps_info)
        del lvap.ht_caps_info['_io']

        ssid = SSID(status.ssid)
        if ssid == SSID():
            ssid = None

        bssid = EtherAddress(status.bssid)
        if bssid == EtherAddress("00:00:00:00:00:00"):
            bssid = None

        lvap.bssid = bssid

        incoming = self.device.blocks[status.iface_id]

        if status.flags.set_mask:
            lvap.downlink = incoming
        else:
            lvap.uplink.append(incoming)

        # if this is not a DL+UL block then stop here
        if not status.flags.set_mask:
            return

        # if an SSID is set and the incoming SSID is different from the
        # current one then raise an LVAP leave event
        if lvap.ssid and ssid != lvap.ssid:
            self.send_client_leave_message_to_self(lvap)
            lvap.ssid = None

        # if the incoming ssid is not none then raise an lvap join event
        if ssid:
            lvap.ssid = ssid
            self.send_client_join_message_to_self(lvap)

        # udpate networks
        networks = list()

        for network in status.networks:
            incoming = (EtherAddress(network.bssid), SSID(network.ssid))
            networks.append(incoming)

        lvap.networks = networks

        self.log.info("LVAP status: %s", lvap)
    def _handle_auth_request(self, request):
        """Handle an incoming AUTH_REQUEST message."""

        sta = EtherAddress(request.sta)

        if sta not in self.manager.lvaps:
            self.log.info("Auth request from unknown LVAP %s", sta)
            return

        lvap = self.manager.lvaps[sta]

        incoming_bssid = EtherAddress(request.bssid)

        # The request bssid is the lvap current bssid, then just reply
        if lvap.bssid == incoming_bssid:
            lvap.bssid = incoming_bssid
            lvap.authentication_state = True
            lvap.association_state = False
            lvap.ssid = None
            lvap.commit()
            self.send_auth_response(lvap)
            return

        # Otherwise check if the requested BSSID belongs to a unique tenant
        for project in self.manager.projects_manager.projects.values():

            if not project.wifi_props:
                continue

            if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED:
                continue

            bssid = project.generate_bssid(lvap.addr)

            if bssid == incoming_bssid:
                lvap.bssid = incoming_bssid
                lvap.authentication_state = True
                lvap.association_state = False
                lvap.ssid = None
                lvap.commit()
                self.send_auth_response(lvap)
                return

        # Finally check if this is a shared bssid
        for project in self.manager.projects_manager.projects.values():

            if not project.wifi_props:
                continue

            if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE:
                continue

            if incoming_bssid in project.vaps:
                lvap.bssid = incoming_bssid
                lvap.authentication_state = True
                lvap.association_state = False
                lvap.ssid = None
                lvap.commit()
                self.send_auth_response(lvap)
                return

        self.log.info("Auth request from unknown BSSID %s", incoming_bssid)
    def _handle_probe_request(self, request):
        """Handle an incoming PROBE_REQUEST message."""

        # Get station
        sta = EtherAddress(request.sta)

        # Incoming
        incoming_ssid = SSID(request.ssid)
        iface_id = request.iface_id
        ht_caps = request.flags.ht_caps
        ht_caps_info = dict(request.ht_caps_info)
        del ht_caps_info['_io']

        msg = "Probe request from %s ssid %s iface_id %u ht_caps %u"

        if not incoming_ssid:
            self.log.debug(msg, sta, "Broadcast", iface_id, ht_caps)
        else:
            self.log.debug(msg, sta, incoming_ssid, iface_id, ht_caps)

        # Check is station is in ACL of any networks
        networks = self.manager.projects_manager.get_available_ssids(sta)

        if not networks:
            self.log.debug("No SSID available at this device")
            return

        # If lvap does not exist then create it. Otherwise just refresh the
        # list of available networks
        if sta not in self.manager.lvaps:

            # spawn new LVAP
            self.log.info("Spawning new LVAP %s on %s", sta, self.device.addr)

            assoc_id = randint(1, 2007)

            lvap = LVAP(sta, assoc_id=assoc_id)
            lvap.networks = networks
            lvap.ht_caps = ht_caps
            lvap.ht_caps_info = ht_caps_info

            # this will trigger an LVAP ADD message
            lvap.blocks = self.device.blocks[request.iface_id]

            # save LVAP in the runtime
            self.manager.lvaps[sta] = lvap

            # Send probe response
            self.send_probe_response(lvap, incoming_ssid)

            return

        lvap = self.manager.lvaps[sta]

        # If this probe request is not coming from the same interface on which
        # this LVAP is currenly running then ignore the probe
        if lvap.blocks[0].block_id != iface_id:
            return

        # If LVAP is not running then ignore
        if not lvap.is_running():
            return

        # Update list of available networks
        lvap.networks = networks
        lvap.commit()

        # Send probe response
        self.send_probe_response(lvap, incoming_ssid)
    def on_read(self, future):
        """Assemble message from agent.

        Appends bytes read from socket to a buffer. Once the full packet
        has been read the parser is invoked and the buffers is cleared. The
        parsed packet is then passed to the suitable method or dropped if the
        packet type in unknown.
        """

        try:
            self.buffer = self.buffer + future.result()
        except StreamClosedError as stream_ex:
            self.log.error(stream_ex)
            return

        hdr = self.proto.HEADER.parse(self.buffer)

        if len(self.buffer) < hdr.length:
            remaining = hdr.length - len(self.buffer)
            future = self.stream.read_bytes(remaining)
            future.add_done_callback(self.on_read)
            return

        # Check if we know the message type
        if hdr.tsrc.action not in self.proto.PT_TYPES:
            self.log.warning("Unknown message type %u, ignoring.",
                             hdr.tsrc.action)
            return

        # Check if the Device is among the ones we known
        addr = EtherAddress(hdr.device)

        if addr not in self.manager.devices:
            self.log.warning("Unknown Device %s, closing connection.", addr)
            self.stream.close()
            return

        device = self.manager.devices[addr]

        # Log message informations
        parser = self.proto.PT_TYPES[hdr.tsrc.action][0]
        name = self.proto.PT_TYPES[hdr.tsrc.action][1]
        msg = parser.parse(self.buffer)
        self.log.debug("Got %s message from %s seq %u", name,
                       EtherAddress(addr), msg.seq)

        # If Device is not online and is not connected, then the only message
        # type we can accept is HELLO_RESPONSE
        if not device.is_connected():

            if msg.tsrc.action != self.proto.PT_HELLO_SERVICE:
                if not self.stream.closed():
                    self.wait()
                return

            # This is a new connection, set pointer to the device
            self.device = device

            # The set pointer from device connection to this object
            device.connection = self

            # Transition to connected state
            device.set_connected()

            # Start hb worker
            self.hb_worker.start()

            # Send caps request
            self.send_caps_request()

        # If device is not online but it is connected, then we can accept both
        # HELLO_RESPONSE and CAP_RESPONSE message
        if device.is_connected() and not device.is_online():
            valid = (self.proto.PT_HELLO_SERVICE,
                     self.proto.PT_CAPABILITIES_SERVICE)
            if msg.tsrc.action not in valid:
                if not self.stream.closed():
                    self.wait()
                return

        # Otherwise handle message
        try:
            self.handle_message(name, msg)
        except Exception as ex:
            self.log.exception(ex)
            self.stream.close()

        if not self.stream.closed():
            self.wait()
Beispiel #14
0
    def addr(self, addr):
        """ Set the station address. """

        self.params['addr'] = EtherAddress(addr)
Beispiel #15
0
    def get(self, *args, **kwargs):
        """List the LVAPs.

        Args:

            [0], the project id (mandatory)
            [1]: the lvap address (optional)

        Example URLs:

            GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/lvaps

            [
                {
                    "addr": "60:F4:45:D0:3B:FC",
                    "assoc_id": 732,
                    "association_state": true,
                    "authentication_state": true,
                    "blocks": [
                        ...
                    ],
                    "bssid": "52:31:3E:D0:3B:FC",
                    "encap": "00:00:00:00:00:00",
                    "ht_caps": true,
                    "ht_caps_info": {
                        "DSSS_CCK_Mode_in_40_MHz": false,
                        "Forty_MHz_Intolerant": false,
                        "HT_Delayed_Block_Ack": false,
                        "HT_Greenfield": false,
                        "LDPC_Coding_Capability": true,
                        "L_SIG_TXOP_Protection_Support": false,
                        "Maximum_AMSDU_Length": false,
                        "Reserved": false,
                        "Rx_STBC": 0,
                        "SM_Power_Save": 3,
                        "Short_GI_for_20_MHz": true,
                        "Short_GI_for_40_MHz": true,
                        "Supported_Channel_Width_Set": true,
                        "Tx_STBC": false
                    },
                    "networks": [
                        [
                            "52:31:3E:D0:3B:FC",
                            "EmPOWER"
                        ]
                    ],
                    "pending": [],
                    "ssid": "EmPOWER",
                    "state": "running",
                    "wtp": {
                        ...
                    }
                }
            ]

            GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/lvaps/
                60:F4:45:D0:3B:FC

            {
                "addr": "60:F4:45:D0:3B:FC",
                "assoc_id": 732,
                "association_state": true,
                "authentication_state": true,
                "blocks": [
                    ...
                ],
                "bssid": "52:31:3E:D0:3B:FC",
                "encap": "00:00:00:00:00:00",
                "ht_caps": true,
                "ht_caps_info": {
                    "DSSS_CCK_Mode_in_40_MHz": false,
                    "Forty_MHz_Intolerant": false,
                    "HT_Delayed_Block_Ack": false,
                    "HT_Greenfield": false,
                    "LDPC_Coding_Capability": true,
                    "L_SIG_TXOP_Protection_Support": false,
                    "Maximum_AMSDU_Length": false,
                    "Reserved": false,
                    "Rx_STBC": 0,
                    "SM_Power_Save": 3,
                    "Short_GI_for_20_MHz": true,
                    "Short_GI_for_40_MHz": true,
                    "Supported_Channel_Width_Set": true,
                    "Tx_STBC": false
                },
                "networks": [
                    [
                        "52:31:3E:D0:3B:FC",
                        "EmPOWER"
                    ]
                ],
                "pending": [],
                "ssid": "EmPOWER",
                "state": "running",
                "wtp": {
                    ...
                }
            }

        """

        project_id = uuid.UUID(args[0])
        project = self.service.projects[project_id]

        return project.lvaps \
            if len(args) == 1 else project.lvaps[EtherAddress(args[1])]
    def _handle_assoc_request(self, request):
        """Handle an incoming ASSOC_REQUEST message."""

        sta = EtherAddress(request.sta)

        ht_caps = request.flags.ht_caps
        ht_caps_info = dict(request.ht_caps_info)
        del ht_caps_info['_io']

        if sta not in self.manager.lvaps:
            self.log.info("Assoc request from unknown LVAP %s", sta)
            return

        lvap = self.manager.lvaps[sta]

        incoming_bssid = EtherAddress(request.bssid)

        if lvap.bssid != incoming_bssid:
            self.log.info("Assoc request for invalid BSSID %s", incoming_bssid)
            return

        incoming_ssid = SSID(request.ssid)

        # Check if the requested SSID is from a unique project
        for project in self.manager.projects_manager.projects.values():

            if not project.wifi_props:
                continue

            if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED:
                continue

            bssid = project.generate_bssid(lvap.addr)

            if bssid != incoming_bssid:
                self.log.info("Invalid BSSID %s", incoming_bssid)
                continue

            if project.wifi_props.ssid == incoming_ssid:
                lvap.bssid = incoming_bssid
                lvap.authentication_state = True
                lvap.association_state = True
                lvap.ssid = incoming_ssid
                lvap.ht_caps = ht_caps
                lvap.ht_caps_info = ht_caps_info
                lvap.commit()
                self.send_assoc_response(lvap)
                return

        # Check if the requested SSID is from a unique project
        for project in self.manager.projects_manager.projects.values():

            if not project.wifi_props:
                continue

            if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE:
                continue

            if incoming_bssid not in project.vaps:
                self.log.info("Invalid BSSID %s", incoming_bssid)
                continue

            if project.wifi_props.ssid == incoming_ssid:
                lvap.bssid = incoming_bssid
                lvap.authentication_state = True
                lvap.association_state = True
                lvap.ssid = incoming_ssid
                lvap.ht_caps = ht_caps
                lvap.ht_caps_info = ht_caps_info
                lvap.commit()
                self.send_assoc_response(lvap)
                return

        self.log.info("Unable to find SSID %s", incoming_ssid)
    def sta(self, sta):
        """ Set the station address. """

        self.params['sta'] = EtherAddress(sta)
    def handle_lvap_response(self, response, *_):
        """Handle BIN_COUNTERS_RESPONSE message."""

        # get lvap mac address
        sta = EtherAddress(response.sta)
        sta = sta.to_str()

        # update this object

        tx_samples = response.stats[0:response.nb_tx]
        rx_samples = response.stats[response.nb_tx:-1]

        old_tx_bytes = self.lvap_counters[sta][
            "tx_bytes"] if sta in self.lvap_counters else 0.0
        old_rx_bytes = self.lvap_counters[sta][
            "rx_bytes"] if sta in self.lvap_counters else 0.0

        old_tx_packets = self.lvap_counters[sta][
            "tx_packets"] if sta in self.lvap_counters else 0.0
        old_rx_packets = self.lvap_counters[sta][
            "rx_packets"] if sta in self.lvap_counters else 0.0

        if not (sta in self.lvap_counters):
            self.lvap_counters[sta] = {}

        self.lvap_counters[sta]["tx_bytes"] = self.fill_bytes_samples(
            tx_samples)
        self.lvap_counters[sta]["rx_bytes"] = self.fill_bytes_samples(
            rx_samples)

        self.lvap_counters[sta]["tx_packets"] = self.fill_packets_samples(
            tx_samples)
        self.lvap_counters[sta]["rx_packets"] = self.fill_packets_samples(
            rx_samples)

        self.lvap_counters[sta]["tx_bps"] = 0
        self.lvap_counters[sta]["rx_bps"] = 0
        self.lvap_counters[sta]["tx_pps"] = 0
        self.lvap_counters[sta]["rx_pps"] = 0

        if sta in self.lvap_last and self.lvap_last[sta] != None:

            delta = time.time() - self.lvap_last[sta]

            self.lvap_counters[sta]["tx_bps"] = \
                self.update_stats(delta, old_tx_bytes, self.lvap_counters[sta]["tx_bytes"])

            self.lvap_counters[sta]["rx_bps"] = \
                self.update_stats(delta, old_rx_bytes, self.lvap_counters[sta]["rx_bytes"])

            self.lvap_counters[sta]["tx_pps"] = \
                self.update_stats(delta, old_tx_packets, self.lvap_counters[sta]["tx_packets"])

            self.lvap_counters[sta]["rx_pps"] = \
                self.update_stats(delta, old_rx_packets, self.lvap_counters[sta]["rx_packets"])

        # generate data points
        points = []
        timestamp = datetime.utcnow()

        fields = {
            "tx_bytes": float(self.lvap_counters[sta]["tx_bytes"]),
            "rx_bytes": float(self.lvap_counters[sta]["rx_bytes"]),
            "tx_packets": float(self.lvap_counters[sta]["tx_packets"]),
            "rx_packets": float(self.lvap_counters[sta]["rx_packets"]),
            "tx_bps": float(self.lvap_counters[sta]["tx_bps"]),
            "rx_bps": float(self.lvap_counters[sta]["rx_bps"]),
            "tx_pps": float(self.lvap_counters[sta]["tx_pps"]),
            "rx_pps": float(self.lvap_counters[sta]["rx_pps"])
        }

        tags = dict(self.params)
        tags["sta"] = sta

        sample = {
            "measurement": 'lvap_counters_stats',
            "tags": tags,
            "time": timestamp,
            "fields": fields
        }

        points.append(sample)

        # save to db
        self.write_points(points)

        # handle callbacks
        self.handle_callbacks()

        # set last iteration time
        self.lvap_last[sta] = time.time()

        # handle rc stats response
        self.handle_class_rc_response(sta)