source: ReferenceDesigns/w3_802.11/python/wlan_exp/node_sta.py

Last change on this file was 6320, checked in by chunter, 5 years ago

1.8.0 release wlan-exp

File size: 12.1 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3------------------------------------------------------------------------------
4Mango 802.11 Reference Design Experiments Framework - Client (STA) Node
5------------------------------------------------------------------------------
6License:   Copyright 2019 Mango Communications, Inc. All rights reserved.
7           Use and distribution subject to terms in LICENSE.txt
8------------------------------------------------------------------------------
9
10"""
11
12import wlan_exp.node as node
13import wlan_exp.cmds as cmds
14
15
16__all__ = ['WlanExpNodeSta']
17
18
19class WlanExpNodeSta(node.WlanExpNode):
20    """wlan_exp Node class for the 802.11 Reference Design STA MAC project
21   
22    Args:
23        network_config (transport.NetworkConfiguration) : Network configuration of the node
24    """
25   
26    #-------------------------------------------------------------------------
27    # Node Commands
28    #-------------------------------------------------------------------------
29    def configure_bss(self, bssid=False, ssid=None, channel=None, beacon_interval=False, ht_capable=None):
30        """Configure the BSS information of the node
31       
32        Each node is either a member of no BSS (colloquially "unassociated")
33        or a member of one BSS.  A node requires a minimum valid set of BSS
34        information to be a member of a BSS. The minimum valid set of BSS
35        information for an STA is:
36
37            #. BSSID: 48-bit MAC address
38            #. Channel: Logical channel for Tx/Rx by BSS members
39            #. SSID: Variable length string (ie the name of the network)
40
41        If a node is not a member of a BSS (i.e. ``n.get_network_info()`` returns
42        ``None``), then the node requires all parameters of a minimum valid
43        set of BSS information be specified (i.e. BSSID, Channel, and SSID). 
44       
45        See https://warpproject.org/trac/wiki/802.11/wlan_exp/bss
46        for more documentation on BSS information / configuration.
47
48       
49        Args:
50            bssid (int, str):  48-bit ID of the BSS either as a integer or
51                colon delimited string of the form ``'01:23:45:67:89:ab'``
52            ssid (str):  SSID string (Must be 32 characters or less)
53            channel (int): Channel number on which the BSS operates
54            beacon_interval (int): Integer number of beacon Time Units in [10, 65534]
55                (http://en.wikipedia.org/wiki/TU_(Time_Unit); a TU is 1024 microseconds);
56                A value of None will disable beacons;  A value of False will not
57                update the current beacon interval.
58            ht_capable (bool):  Is the PHY mode HTMF (True) or NONHT (False)?
59        """
60        if (self.is_scanning() is True) and (bssid is None):
61            print('Warning: network scan is still running when BSS was set to None. Use stop_active_scan if needed.')
62       
63        resp_args = self.send_cmd(cmds.NodeConfigBSS(bssid=bssid, ssid=ssid, channel=channel,
64                                                     beacon_interval=beacon_interval, ht_capable=ht_capable))
65       
66        # Process response arguments
67        if (resp_args is not False):
68            status  = resp_args[0]
69            msg     = "ERROR:\n"
70            ret_val = True
71           
72            # Check status
73            if (status & cmds.ERROR_CONFIG_BSS_BSSID_INVALID):
74                if type(bssid) in [int, long]:
75                    import wlan_exp.util as util
76                    self.bssid = util.mac_addr_to_str(bssid)
77                msg    += "    BSSID {0} was invalid.\n".format(self.bssid)
78                ret_val = False
79           
80            if (status & cmds.ERROR_CONFIG_BSS_BSSID_INSUFFICIENT_ARGUMENTS):
81                msg    += "    Insufficient arguments to create BSS.  Must provide:\n"
82                if (bssid is False): 
83                    msg    += "        BSSID\n"
84                if (ssid is None):
85                    msg    += "        SSID\n"
86                if (channel is None):
87                    msg    += "        CHANNEL\n"
88                ret_val = False
89           
90            if (status & cmds.ERROR_CONFIG_BSS_CHANNEL_INVALID):
91                msg    += "    Channel {0} was invalid.\n".format(channel)
92                ret_val = False
93           
94            if (status & cmds.ERROR_CONFIG_BSS_BEACON_INTERVAL_INVALID):
95                msg    += "    Beacon interval {0} was invalid.\n".format(beacon_interval)
96                ret_val = False
97           
98            if (status & cmds.ERROR_CONFIG_BSS_HT_CAPABLE_INVALID):
99                msg    += "    HT capable {0} was invalid.\n".format(ht_capable)
100                ret_val = False
101           
102            if not ret_val:
103                print(msg)
104
105
106    def disassociate(self):
107        """Causes the STA node to transmit a de-authenticate packet and to reset
108        its BSS status to null. After this method the STA will be disassociated from
109        its former BSS.
110
111        """
112        self.send_cmd(cmds.NodeDisassociate())
113
114
115    def is_associated(self, ap):
116        """Is the AP in the STA's association table?
117
118        Args:
119            ap (WlanDevice):  WLAN Device
120
121        Returns:
122            associated (bool):  Boolean describing whether the STA is associated with the AP
123
124        """
125        ret_val  = False
126
127        if ap is not None:
128            my_station_info = self.get_station_info_list(ap)
129
130            if my_station_info is not None:
131                ret_val = True
132
133        return ret_val
134
135
136
137    #-------------------------------------------------------------------------
138    # STA specific Commands
139    #-------------------------------------------------------------------------
140    def _check_allowed_rate(self, mcs, phy_mode, verbose=False):
141        """Check that rate parameters are allowed
142
143        Args:
144            mcs (int):           Modulation and coding scheme (MCS) index
145            phy_mode (str, int): PHY mode (from util.phy_modes)
146
147        Returns:
148            valid (bool):  Are all parameters valid?
149        """
150        # TODO: implement STA-specific rate checking here
151        #  Allow all supported rates for now
152
153        return self._check_supported_rate(mcs, phy_mode, verbose)
154
155
156
157    def set_aid(self, aid):
158        """Set the Association ID (AID) of the STA.
159
160        Normally the AID is assigned by the AP during the probe/authentication/association
161        handshake. However if the BSS configuration of the STA is set via the
162        configure_bss() method there is no AP-assigned AID. Thankfully this is only a
163        cosmetic problem. The reference code does not use the AID for any MAC processing.
164        By default the AID is only used to set the hex display at the STA node. This
165        method will have the same affect.
166
167        Args:
168            aid (int): Association ID (must be in [1, 255])
169        """
170        self.send_cmd(cmds.NodeSTASetAID(aid))
171   
172
173    def join_network(self, ssid, bssid=None, channel=None, timeout=5.0):
174        """Join the specified network (BSS).
175
176        By specifying the SSID, the STA will try to join the given network.  If
177        the bssid and channel of the network are also known, they can be
178        provided.  Otherwise, the STA will scan for the given SSID to find the
179        corresponding bssid and channel.  If the SSID is None, then any
180        on-going join process will be halted. 
181       
182        If the node is currently associated with the given BSS, then the node
183        state is not changed and this method will return "success" immediately.
184       
185        By default, the join process has a timeout that will automatically
186        halt the join process once the timeout is exceeded.  Depending on the
187        scan parameters, this timeout value may need to be adjusted to allow
188        the STA to scan all channels before the timeout period is exceeded. 
189        If the timeout is None, then the method will return immediately and
190        the methods is_joining() and get_network_info() can be used to determine
191        if the STA has joined the BSS.
192       
193        If this method starts an active scan, the scan will use the parameters
194        previously configured with node.set_scan_parameters().
195
196        Args:
197            ssid (str):  SSID string (Must be 32 characters or less); a value
198                of None will stop any current join process.
199            bssid (int, str):  48-bit ID of the BSS either as a integer or
200                colon delimited string of the form:  XX:XX:XX:XX:XX:XX
201            channel (int): Channel number on which the BSS operates
202            timeout (float):  Time to complete the join process; a value of
203                None will cause the method to return immediately and allow
204                the join process to continue forever until the node has joined
205                the network or the join has failed.
206               
207        """
208        status = True
209       
210        # Check if node is currently associated with ssid / bssid
211        #     - _check_associated_node() returns True if ssid is None
212        if self._check_associated_node(ssid, bssid):
213            # Still need to send the Join command to stop join process
214            if ssid is None:
215                self.send_cmd(cmds.NodeSTAJoin(ssid=None))
216        else:
217            # Perform the join process
218
219            # Send the join command
220            status = self.send_cmd(cmds.NodeSTAJoin(ssid=ssid, bssid=bssid, channel=channel))
221           
222            if timeout is not None:
223                import time
224               
225                # Get the start time so that the timeout can be enforced
226                start_time = time.time()
227
228                # Check when join process completes that STA has joined BSS               
229                while ((time.time() - start_time) < timeout):
230                    if self.is_joining():
231                        # Sleep for 0.1 seconds to not flood the node
232                        time.sleep(0.1)
233                    else:
234                        status = self._check_associated_node(ssid, bssid)
235                        break
236       
237        return status       
238
239
240    def is_joining(self):
241        """Queries if the STA is currently attempting to join a network. The join
242        state machine runs until the target network is successfully joined or
243        the joing process is terminated by the user. This method tests whether
244        the join process is still running. To check success or failure of the
245        join process, use node.get_network_info().
246       
247        Returns:
248            status (bool):
249
250                * True      -- Inidcates node is currently in the join process
251                * False     -- Indicates node is not currently in the join process
252        """
253        return self.send_cmd(cmds.NodeSTAJoinStatus())
254
255
256
257    #-------------------------------------------------------------------------
258    # Internal STA methods
259    #-------------------------------------------------------------------------
260    def _check_associated_node(self, ssid, bssid):
261        """Check if node is currently associated to the given BSS
262       
263        This method only checks that the bss_info of the node matches the
264        provided ssid / bssid and is not a substitute for is_associated().
265       
266        This method will only check the bssid after it matches the SSID.  If
267        either argument is None, then it will not be checked.  If SSID is
268        None, then the method will return True.
269       
270        Args:
271            ssid  (str):  SSID of the BSS
272            bssid (str):  BSSID of the BSS
273
274        Returns:
275            associated (bool): Do the SSID / BSSID matche the BSS of the node?
276        """
277        if ssid is not None:
278            network_info = self.get_network_info()
279       
280            if network_info is None:
281                return False
282           
283            if (network_info['ssid'] != ssid):
284                return False
285       
286            if bssid is not None:
287                if (network_info['bssid'] != bssid):
288                    return False
289       
290        return True
291
292
293# End class
Note: See TracBrowser for help on using the repository browser.